Do index names have to be unique accross the entire sql server database, or just for that table?
For example, should I name my index: IX_OrderLoadCarrierDelivery_OrderLoadID
for the OrderLoadID column of the OrderLoadCarrierDelivery table. Or should I just name it IX_OrderLoadID
Thanks!
They have to be unique for the table or view they were created for.
Here is a reference on msdn that details this.
FTA:
index_name
Is the name of the index.
Index names must be unique within a
table or view but do not have to be
unique within a database. Index names
must follow the rules of identifiers.
I believe the convention is
IX_FieldName
No, per table.
That is, a unique (object_id, name) column pair in sys.indexes rather then just (name) in sys.objects (ignoring schema_id)
I'd also use something like IX_SingleColumn or IX_ParentTable. Adding table is superfluous unlike a default or check constraint, say, that is unique per DB
They have to be unique as everything gets stored in sysobjects with the name as key
If you use SQL management studio, it's IX_Table_Field syntax
Related
Model: merchants have one to many customers and customers have one to many accounts. Accounts have names. All three tables have unique IDs for each row.
Constraint: For a given merchant, the account names must be unique.
How do we enforce this constraint in a SQL Server database schema?
Here'some ideas we've considered:
We could add MerchantId to the Account table and create a unique constraint, but it's a redundant column to maintain given that CustomerId is already there. We'd need to make sure the combination of MerchantId and CustomerId are themselves consistent, so we'd make the foreign key between Account and Customer include both columns, even though CustomerId is already a unique identifier.
We could add a check constraint to the Account table and use a UDF to check the constraint rule. But then a Customer could conceivable be assigned to a different Merchant, and the check constraint on Account wouldn't be checked. So we'd have to add another constraint on the Customer table, which starts to seem like we're doing it wrong, especially as the real model gets more complex than described here.
We could enforce the constraint via triggers, but this doesn't seem to improve upon the shortcomings with using check constraints.
Maybe the best idea of a solution is to create a view joining the 3 tables and create a unique index on that view. That would be an indexed view. When you index a view it gets persisted just like a regular table, but it's updated automagically by the database engine as part of regular DML commands.
There are lots of requirements and restrictions on what you can and cannot do, those are in the docs I linked to above, but I think you can get away with it.
The code would go like this:
CREATE VIEW dbo.MerchantAccounts
WITH SCHEMABINDING
AS
SELECT m.MerchantKey, a.AccountKey, a.Name
FROM dbo.Accounts a
INNER JOIN dbo.Customers c
ON a.CustomerKey = c.CustomerKey
INNER JOIN dbo.Merchants m
ON c.MerchantKey = m.MerchantKey;
GO
CREATE UNIQUE CLUSTERED INDEX IX_MerchantKey_AccountName
ON dbo.MerchantAccounts (MerchantKey, Name);
GO
I included 3 columns in the view but only 2 are part of the unique clustered index. So you must not have duplicated MarchantKey,AccountName to begin with, and after that the database engine will ensure that for you.
You don't need to change your table and your relationships as long as you don't violate the requirements.
You can include more columns than just the key columns in your indexes view, and that can help performance for some queries. That's up to you. Just be aware that the resultset of the view (the equivalent of SELECT * FROM dbo.MerchantAccounts) will be persisted on your database and will take up space. So the more columns you add the bigger the view gets and the more expensive it gets to maintain it up to date.
When I create a full text index on a temporary table #Table in a query? I got Invalid name object #Table.
Is creating full text index possible in sql server?
According to the documentation, no it is not possible:
A full-text index must be defined on a base table; it cannot be
defined on a view, system table, or temporary table.
This should be clarified to point out that since the version that documentation was written for, indexed views were added to SQL Server, and documentation there states that:
one full-text index is allowed per table or indexed view
I am trying to modify a stored procedure ( adding a new column in select statement) but I am getting this error:
Cannot use a CONTAINS or FREETEXT predicate on table or indexed view 'vwPersonSearch' because it is not full-text indexed.
When I try to create a Full text index on view 'vwPersonSearch' using SQL server 2008 R 2 management studio, I am getting this error:
A unique column must be defined on this table/view.
Please suggest solution to it
To create a full text index, you must specify a key index, which must be a unique, single-key, non-nullable column. An integer column type is recommended for best performance.
See http://technet.microsoft.com/en-us/library/ms187317.aspx for more details.
You may alter a column to be unique if that's one that could be or add an id of some sort to do that part.
In SQL Server 2008 and given
TableA(A_ID, A_Data)
TableB(B_ID, B_Data)
ViewC(A_or_B_ID, A_or_B_Data)
is it possible to define TableZ(A_or_B_ID, Z_Data) such that Z.A_or_B_ID column is constrained to the values found in ViewC? Can this be done with a foreign key against the view?
You can't reference a view in a foreign key.
In older SQL Server editions foreign keys were possible only through triggers. You can mimic a custom foreign key by creating an Insert trigger which checks whether the inserted value appears in one of the relevant tables as well.
If you really need A_or_B_ID in TableZ, you have two similar options:
1) Add nullable A_ID and B_ID columns to table z, make A_or_B_ID a computed column using ISNULL on these two columns, and add a CHECK constraint such that only one of A_ID or B_ID is not null
2) Add a TableName column to table z, constrained to contain either A or B. now create A_ID and B_ID as computed columns, which are only non-null when their appropriate table is named (using CASE expression). Make them persisted too
In both cases, you now have A_ID and B_ID columns which can have appropriate foreign
keys to the base tables. The difference is in which columns are computed. Also, you
don't need TableName in option 2 above if the domains of the 2 ID columns don't
overlap - so long as your case expression can determine which domain A_or_B_ID
falls into
(Thanks to comment for fixing my formatting)
Sorry, you cannot FK to a view in SQL Server.
There is another option. Treat TableA and TableB as subclasses of a new table called TablePrime. Adjust TableB's ID values so they do not coincide with TableA's ID values. Make the ID in TablePrime the PK and insert all of TableA's and TableB's (adjusted) IDs into TablePrime. Make TableA and TableB have FK relationships on their PK to the same ID in TablePrime.
You now have the supertype/subtype pattern, and can make constraints to TablePrime (when you want either-A-or-B) or one of the individual tables (when you want only A or only B).
If you need more details, please ask. There are variations that will let you make sure A and B are mutually exclusive, or maybe the thing you're working with can be both at the same time. It's best to formalize that in the FKs if possible.
It is easier to add a constraint that references a user defined function that makes the check for you, fCheckIfValueExists(columnValue) which returns true if the value exists and false if it doesn't.
The upside is that it can receive multiple columns, perform calculations with them, accept nulls and accept values that don't precisely correspond to a primary key or compare with results of joins.
Downside is that the optimizer can not use all his foreign key tricks.
Sorry,
In the strict sense of the word, no you cannot set foreign keys on views. Here is why:
InnoDB is the only built-in storage engine for MySQL that features foreign keys. Any InnoDB table will be registered in information_schema.tables with engine = 'InnoDB'.
Views, while registered in information_schema.tables, has a NULL storage engine. There are no mechanisms in MySQL to have foreign keys on any table that has an undefined storage engine.
Thanks!
When there are one of more columns that reference another, I'm struggling for the best way to update that column while maintaining referential integrity. For example, if I have a table of labels and descriptions and two entries:
Label | Description
------------------------------------
read | This item has been read
READ | You read this thing already
Now, I don't want these duplicates. I want to add a constraint to the column that doesn't allow values that are case-insensitively duplicates, as in the example. However, I have several rows of several other tables referencing 'READ', the one I want to drop.
I know Postgres knows which fields of other rows are referencing this, because I can't delete it as long as they are there. So, how could I get any field referencing this to update to 'read'? This is just an example, and I actually have a few places I want to do this. Another example is actually an int primary key for a few tables, where I want to add a new table as a sort of 'base table' that the existing ones extend and so they'll all need to have unique IDs now, which means updating the ones they have.
I am open to recipes for functions I can add to do this, tools I can utilize, or anything else.
If you have many rows referencing READ, you could alter the foreign key to be on cascade update, update that table set Label = 'read' where Label = 'READ' and everything will get automagically fixed. After that you can alter the constraint again to be as it was before.
To find all the tables referencing the column, you can use
select TABLE_NAME,COLUMN_NAME,CONSTRAINT_NAME,
REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME from
INFORMATION_SCHEMA.KEY_COLUMN_USAGE where
REFERENCED_TABLE_NAME = '<table>' AND REFERENCED_COLUMN_NAME = '<column>'
For the future you could create an unique index on the column "label", for example:
CREATE UNIQUE INDEX index_name ON table ((lower(label)));
Or check the manual.
That would help you to avoid this situation for the next time.