Composite Keys Constraints - sql

I am creating a database for handbag shopping website in which i have a table called dbo.ProductMatching
CREATE TABLE [dbo].[ProductMatching](
[ProductMatchingID] [int] NOT NULL IDENTITY, -- This can be Made Primary Key but i want to use composite keys
[MainProductID] [int] NOT NULL,
[MainProductColourID] [int] NOT NULL,
[ReferenceProductID] [int] NULL,
[ReferenceProductColourID] [int] NOT NULL,
[CreatedOn] [datetime] NOT NULL,
[UpdatedOn] [datetime] NOT NULL
) ON [PRIMARY]
What i want to do is Make (MainProductID,MainProductColourID) unique and for each this combination i want to make combination of (ReferenceProductID,ReferenceProductColourID) unique also.
e.g suppose i have combination of (MainProductID,MainProdcutColourID) = (1,1) it referes to (ReferenceProductID,ReferenceProductColourID) = (2,2) Then (1,1) can not refer to another (2,3) combination.. i cant make the whole four keys composite keys because it would allow reference (1,1) to (2,3) combination..
i know i can just make exists statement when inserting data or make a before insert trigger or update trigger for data consistency but what i want to know if this can be done with using composite keys.. if not what are other available options...

If I understand the problem then two simple unique constraints
MainProductID,MainProductColourID
and
MainProductID,ReferenceProductID
And I would use
MainProductID,MainProductColourID as a composite PK
(that will satisfy that unique constraint)
If that is wrong then please show more examples that are correct
And more that are incorrect with a reason

Related

How can I define a UNIQUE constraint that applies to multiple columns in a DataSet table?

I have the following table defined in a .sql script file.
CREATE TABLE [HwComponent](
[HwComponentId] [int] NOT NULL,
[HwComponentTypeId] [int] NOT NULL,
[ManufactureId] [int] NOT NULL,
[SerialNumber] [nvarchar](100) NOT NULL,
[AssignmentType] [nvarchar](1000) NOT NULL,
[IsFunctional] [nvarchar](10) NOT NULL,
[Note] [nvarchar](4000) NULL,
CONSTRAINT [PK_HwComponent] PRIMARY KEY ([HwComponentId]),
CONSTRAINT (FK1_HwComponent] FOREIGN KEY ([HwComponentTypeId]) REFERENCES [HwComponentType] ([HwComponentTypeId)] ON DELETE NO ACTION ON UPDATE NO ACTION
CONSTRAINT (FK2_HwComponent] FOREIGN KEY ([HwComponentTypeId], [ManufactureId]) REFERENCES [HwComponentTypeManufacturerInfo] ([HwComponentTypeId], [ManufactureId]) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT (UI1_HwComponent] UNIQUE ([HwComponentTypeId], [ManufactureId], [SerialNumber]))
GO
I now need to define a new table in the DataSet Designer to match.
I believe I have everything defined correctly, except the UNIQUE constraint that requires all 3 columns be considered together as the unique constraint.
How do I define the UNIQUE constraint for this table in the DataSet Designer?
SQL CE Service 4.0 SP1:
VS Prof 2017 - Version 15.8.7
Your code should work if properly formatted. You have parens where you shouldn't:
CREATE TABLE [HwComponent](
[HwComponentId] [int] NOT NULL,
[HwComponentTypeId] [int] NOT NULL,
[ManufactureId] [int] NOT NULL,
[SerialNumber] [nvarchar](100) NOT NULL,
[AssignmentType] [nvarchar](1000) NOT NULL,
[IsFunctional] [nvarchar](10) NOT NULL,
[Note] [nvarchar](4000) NULL,
CONSTRAINT PK_HwComponent PRIMARY KEY ([HwComponentId]),
CONSTRAINT FK1_HwComponent FOREIGN KEY ([HwComponentTypeId]) REFERENCES [HwComponentType] ([HwComponentTypeId)] ON DELETE NO ACTION ON UPDATE NO ACTION
CONSTRAINT K2_HwComponent FOREIGN KEY ([HwComponentTypeId], [ManufactureId]) REFERENCES [HwComponentTypeManufacturerInfo] ([HwComponentTypeId], [ManufactureId]) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT UI1_HwComponent UNIQUE ([HwComponentTypeId], [ManufactureId], [SerialNumber])
);
I would advise you to get rid of all the square braces. They just make the code harder to write and to read and to modify.
Does this work for you?
CREATE UNIQUE INDEX ixYourConstraint ON HwComponent (col1, col2);
This similar post might be of help to you:
MsSql Compact, unique constraint on two and more columns
Thanks Algef and Gordon for you responses.
Sorry about the confusion. My bad. :-)
The SQL sample works fine. I used it as an example only. I actually need to represent this table exactly using the DataSet Designer in VS. The table should look something like the following when done.
HwComponent Table in the DataSet Designer
My problem is I'm not having success in defining the UNIQUE group properly in the DataSet Designer.
I need to define a UNIQUE GROUP that consists of the HwComponentTypeId, ManufactureId and SerialNumber columns.
Any ideas?
Thanks again for any help

Cannot define PRIMARY KEY Constraint on nullable column when column is already NOT NULL

I have a table called Cases that has information about interviews such as IV_Date, IV_Length, Interviewer, etc. I also have a field within Cases called Case_Code (a varchar) which is a six-character (three letters + three numbers) identifier; e.g. "ABC123" or "ZZZ999." There is a foreign key on ContactID (an int), which points to a Contact table. I have created a computed column which is the PRIMARY KEY of this Cases table, called CaseID. CaseID is simply a concatenation of Case_Code and ContactID. So, ContactID "25" working on case "ZZZ999" is given a CaseID of "ZZZ99925". Neither Case_Code nor ContactID accepts nulls, so CaseID obviously does not. When setting up CaseID I created it as NOT NULL, PRIMARY KEY, and used the formula "[Case_Code] + CONVERT([varchar], [contactID], 0)". I thought everything was working fine but when I try to rearrange any fields in the SQL Studio table design view, I get thrown this error:
'Cases (dbo)' table
- Unable to create index 'PK_Cases_1'.
Cannot define PRIMARY KEY constraint on nullable column in table 'Cases'.
Could not create constraint. See previous errors.'
I do not understand why I'm getting this error, since all NOT NULL columns in my table contain data. Any help or ideas would be greatly appreciated. Thanks!
Edit with code:
CREATE TABLE [dbo].[Cases](
[ContactID] [int] NOT NULL,
[Case_Code] [varchar](16) NOT NULL,
[Assigned_To] [varchar](100) NULL,
[LEK_Interviewer] [varchar](255) NULL,
[Case_Notes] [varchar](max) NULL,
[IV_Status] [varchar](100) NULL,
[IV_Quality] [numeric](18, 0) NULL,
[IV_Date] [date] NULL,
[IV_Length] [varchar](50) NULL,
[Address] [varchar](100) NULL,
[City] [varchar](100) NULL,
[State] [varchar](50) NULL,
[Zip] [varchar](25) NULL,
[Country] [varchar](50) NULL,
[Total_Honorarium] [money] NULL,
[Currency] [varchar](20) NULL,
[Last_Update] [varchar](50) NULL,
[CaseID] AS ([Case_Code]+CONVERT([varchar],[contactID],0)) PERSISTED NOT NULL,
CONSTRAINT [PK_Cases_1] PRIMARY KEY CLUSTERED
(
[CaseID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
A primary key cannot be applied on a column with a null constraint (nullable). When a table is created, by default every column is nullable.
So first off all we have to remove the null constraint and apply a NOT NULL constraint on the column. To do this execute the following query
ALTER TABLE tbl_name alter column column_name int NOT NULL
After that you can apply a primary key on that same column. To do this execute the following query
ALTER TABLE tbl_name ADD PRIMARY KEY (column_name)
I hope this will help you
I bumped into this, too. You can create a PK on a calculated field, as long as it's marked NOT NULL, but the SQL Server table design interface does not handle this situation; it seems to mark all calculated fields as NULLable when modifying a table.
First, I strongly recommend that you always create and modify your tables with scripts, not the GUI. Doing so gives you a record of what you have and what changes you've made; you can run them to recreate your database as of any point in time. As HLGEM mentioned, you can also keep these scripts in source control. Having these scripts makes it easier to do things which are difficult to do with the GUI, and as you've discovered here, they make it possible to do things which are impossible in the GUI.
Within the table designer, delete your PK. You should then be able to save the table, effecting the reordering of fields you wanted to achieve. Next, you need to drop and recreate the calculated field, and finally you can recreate your PK. E.g.:
ALTER TABLE Cases DROP COLUMN CaseID
ALTER TABLE Cases ADD CaseID AS (Case_Code + CAST(ContactID AS CHAR(6))) PERSISTED NOT NULL
ALTER TABLE Cases ADD CONSTRAINT CPK_Cases PRIMARY KEY CLUSTERED (CaseID)
If you have any indices which reference the calculated field (other than the PK, which we've already dropped), you'll need to delete them before you can drop the calculated field. Be sure to re-create them after, of course.
Finally, while Dean did not support his assertion that calculated fields are bad for PKs, he is correct that it would be simpler to put your PK on { Case_Code, ContactID }. You could then stop persisting CaseID (if you even need it all) and save yourself a little disk space.
Use this query
Alter table tablename
add column datatype identity(1,1)
Don't use computed column as a primary key, very bad idea. In your case, just define the PK on both CaseCode and ContactID columns. In the designer, select both columns, right-click and choose "set prinary key" from the menu.
This appears to be a bug in the SQL Server Management Studio. The easiest approach is to make your changes using the designer. Then generate the change script using:
Right-click > Generate Change Script...
Copy the generated SQL or save it to a file. Then, add "NOT NULL" to the computed column in the CREATE TABLE statement and run the SQL file

When is a SQL Server foreign key table too much?

When I have the below two tables, would the StatusTypes table be considered as overkill? i.e. is there more benefit to using it than not?
In this situation I don't expect to have to load these statuses up in an admin backend in order to add or change/ delete them, but on the other hand I don't often like not using foreign keys.
I'm looking for reasons for and against separating out the status type or keeping it in the Audit table.
Any help would be appreciated.
-- i.e. NEW, SUBMITTED, UPDATED
CREATE TABLE [dbo].[StatusTypes](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](250) NOT NULL,
CONSTRAINT [PK_StatusTypes] PRIMARY KEY CLUSTERED ([ID] ASC)
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Audits](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Description] [nvarchar](500) NULL,
[Country_Fkey] [int] NOT NULL,
[User_Fkey] [int] NOT NULL,
[CreatedDate] [date] NOT NULL,
[LastAmendedDate] [date] NULL,
[Status_Fkey] [int] NOT NULL,
CONSTRAINT [PK_Audits] PRIMARY KEY CLUSTERED ([ID] ASC)
) ON [PRIMARY]
GO
In this situation I like to keep the lookup table to enforce the status being one of a set of types. Some databases have an enum type, or can use check constraints, but this is the most portable method IMO.
However, I make the lookup table containing only a single string column containing the type's name. That way you don't have to actually join to the lookup table and your ORM (assuming you use one) can be completely unaware of it.
In this case the schema would look like:
CREATE TABLE [dbo].[StatusTypes](
[ID] [nvarchar](250) NOT NULL,
CONSTRAINT [PK_StatusTypes] PRIMARY KEY CLUSTERED ([ID] ASC)
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Audits](
[ID] [int] IDENTITY(1,1) NOT NULL,
...
[Status] [nvarchar](250) NOT NULL,
CONSTRAINT [PK_Audits] PRIMARY KEY CLUSTERED ([ID] ASC),
CONSTRAINT [FK_Audit_Status] FOREIGN KEY (Status) REFERENCES StatusTypes(ID)
) ON [PRIMARY]
GO
And a query for audit items of a particular type would be:
SELECT ...
FROM Audits
WHERE Status = 'ACTIVE'
So referential integrity is still enforced but queries don't need an extra join.
I'll offer a counter-argument: Use your development time where it is most useful. Maybe you don't need this runtime-check that much. Maybe you can use your development time for some other check that is more useful.
Is it even likely that an invalid status value will be set? You application surely uses a set of constants or an enum so it is unlikely that some rogue value slips in.
That said, there is a lot of value in ensuring integrity. I like to cover all my "enum" columns with a BETWEEN check constraint which is quickly done and even faster at runtime.

Primary key is foreign keyed to itself in a credible reference manual - How can this work?

I have a DB schema from The Data Model Resource Book, Vol. 1. In it is a table like this:
CREATE TABLE [dbo].[AccountingPeriod](
[AccountingPeriodID] [int] NOT NULL,
[RoleTypeID] [int] NOT NULL,
[PeriodTypeID] [int] NOT NULL,
[AcctgPeriodNum] [int] NOT NULL,
[FromDate] [smalldatetime] NOT NULL,
[ThruDate] [smalldatetime] NOT NULL,
[PartyID] [int] NOT NULL,
PRIMARY KEY CLUSTERED (
[AccountingPeriodID] ASC)
With a constraint defined as:
ALTER TABLE [dbo].[AccountingPeriod] WITH CHECK ADD FOREIGN KEY([AccountingPeriodID])
REFERENCES [dbo].[AccountingPeriod] ([AccountingPeriodID])
The AccountingPeriodID column has a self referencing foreign key that the text claims is a recursive reference column but I think it's an error. I think I need another column to properly store recursive references in this table. Can the author's method be implemented with the table definition supplied, why?
Yes, You need another column which will reference the primary key column of the table itself, for self referencing a table. Self referencing column really does not make any sense.

Indexing for uniqueidentifier column in table

i have created a table where i used unique identifier(GUID) as a primary key of table. Now i need to create a indexing on my table which one will be best for me..i am going to use this table for error logging.
Following is my table structure
CREATE TABLE [dbo].[errors](
[error_id] [uniqueidentifier] NOT NULL,
[assembly_name] [varchar](50) NULL,
[method_name] [varchar](50) NULL,
[person_id] [int] NULL,
[timestamp] [datetime] NULL,
[description] [varchar](max) NULL,
[parameter_list] [varchar](max) NULL,
[exception_text] [nvarchar](max) NULL)
So which table i use as a primary key and index.
Thanks in advance.
You can use that as PK but not good if you use it as clustered index.In that case the GUID will be copied in all the nc index keys and thus makes them much wider and could cause performance issue.Also, this might cause page spilts which is no good.Wide indexes means more space will be used.If you have used GUID to avoid the last page contention issues try to use some sort of hashing technique to make sure that data goes on diff pages.But in that case you have to use same hashing while selecting form table using PK.