How do I avoid duplicates on an SQL primary key? - sql-server

Complete beginner here. I'm trying to create this simple joint table on SSMS but I'm getting this duplicate error regarding the primary key:
Msg 2627, Level 14, State 1, Line 23
Violation of PRIMARY KEY constraint 'PK__FactOffl__B14003C24ECE0589'. Cannot insert duplicate key in object 'dbo.FactOfflineSales'. The duplicate key value is (43659).
What am I doing wrong?
CREATE TABLE FactOfflineSales
(
SalesOrderID int NOT NULL PRIMARY KEY,
SalesOrderNumber nvarchar(20) NOT NULL,
SalesPersonID int NULL,
CustomerID int NULL,
SpecialOfferID int NOT NULL,
TerritoryID int NOT NULL,
ProductID int NOT NULL,
CurrencyRateID int NULL,
OrderQuantity smallint NULL,
UnitPrice money NULL,
SubTotal money NULL,
TaxAmount money NULL,
Freight money NULL,
LineTotal money NULL,
UnitPriceDiscount float NULL,
OrderDate datetime NULL,
ShipDate datetime NULL,
DueDate datetime NULL,
OnlineOrderFlag int NULL
);
INSERT INTO FactOfflineSales (
SalesOrderID
,SalesOrderNumber
,SalesPersonID
,CustomerID
,SpecialOfferID
,TerritoryID
,ProductID
,CurrencyRateID
,OrderQuantity
,UnitPrice
,SubTotal
,TaxAmount
,Freight
,LineTotal
,UnitPriceDiscount
,OrderDate
,ShipDate
,DueDate
,OnlineOrderFlag
)
SELECT
SalesOrderHeader.SalesOrderID
,SalesOrderHeader.SalesOrderNumber
,SalesOrderHeader.SalesPersonID
,SalesOrderHeader.CustomerID
,SalesOrderDetail.SpecialOfferID
,SalesOrderHeader.TerritoryID
,SalesOrderDetail.ProductID
,SalesOrderHeader.CurrencyRateID
,SalesOrderDetail.OrderQty
,SalesOrderDetail.UnitPrice
,SalesOrderHeader.SubTotal
,SalesOrderHeader.TaxAmt
,SalesOrderHeader.Freight
,SalesOrderDetail.LineTotal
,SalesOrderDetail.UnitPriceDiscount
,SalesOrderHeader.OrderDate
,SalesOrderHeader.ShipDate
,SalesOrderHeader.DueDate
,SalesOrderHeader.OnlineOrderFlag
FROM
AdventureWorks2019.Sales.SalesOrderHeader SalesOrderHeader
LEFT JOIN
AdventureWorks2019.Sales.SalesOrderDetail SalesOrderDetail ON SalesOrderHeader.SalesOrderID = SalesOrderDetail.SalesOrderID;

You can not insert the duplicate value in primary key column.
You table FactOfflineSales has primary key on column SalesOrderID which will hold not null and unique values. But looking at your query it seems like there is one-to-many relationship between salesorderheader and salesorderdetails table. so your select query is giving multiple records for single salesorderid, means multiple records with same salesorderid.
It is not allowed to insert duplicate values in FactOfflineSales.salesorderid. Hence, it is throwing an error.
Best practice is to use auto generated sequence for primary key column. You should add one more column in table and declare it as primary key.(something like FactOfflineSales_id)

Your LEFT JOIN on SalesOrderDetail is mutiplying out rows from SalesOrderHeader, from which the primary key comes.
You need to add SalesOrderDetailID to the table, with that (or that and SalesOrderID together) as the primary key

There is a lot going on here. Let me unpack.
A join between tables helps when there is many to many. What does this mean? It means a header has many detail records and a detail record can belong to many headers. If this is not your case, you don't need a join table.
If you really need a join table, you normally do one of two things. The first would be create a composite key on the IDs from both tables. This would only be unique more than once if you load the table with a query that has dupes (solved with DISTINCT). The second (other option) is create a derived key for the primary key (like IDENTITY) and then have the two fields.
As you are learning, neither apply, but you can play with the queries to learn.
See if adding a distinct in the SELECT eliminates dupes. I don't think this will work, but DISTINCT is good to learn.
When the above fails, add a derived key on the table and then rerun your query. You do this by creating this join table with an Id field that is IDENTITY(1,1) for the PRIMARY KEY
As already mentioned by others, your issue is you have dupes on the primary key, which is sales order Id. Why dupes? Because each header has multiple detail records. On record 2, it will fail, as you had the header's id as your primary key.

Related

Is it better to have an Id as primary key or a double foreign key

I want to know what is the most optimized data structure:
I have 2 tables like:
CREATE TABLE Person
(
Id Int NOT NULL PRIMARY KEY,
name varchar(50)
)
CREATE TABLE Group
(
Id Int NOT NULL PRIMARY KEY,
nameOfGroup varchar(50)
)
In my table to connect persons to groups I want to know what is the most optimized way to create it between an ID and then the foreign keys, like that:
CREATE TABLE PersonGroup
(
Id Int DISTINCT NOT NULL PRIMARY KEY,
PersonId Int, -- which is a foreign key to table Person
GroupId Int -- which is a foreign key to table Group
)
OR having the 2 foreign keys as a primary because no one can be 2 times in the same group anyway, like that :
CREATE TABLE PersonGroup
(
PersonId Int NOT NULL, -- which is a foreign key to table Person
GroupId Int NOT NULL, -- which is a foreign key to table Group
CONSTRAINT PK_PersonSgroup PRIMARY KEY (PersonId, GroupId)
)
What is the most optimized between those 2 tables for querying after (if there is more optimize).
Thank you to have read my post.
The first solution (PK identity) is incomplete because you need to have an alternate (or surrogate) key (AK) compound of the two FK.
In the two possibilities, you must know that the order of the two FK in the PK or the AK is very important. This order must follow the usual querying way. So the questions are
do you use first the group then the person in queries ?
do you use first the personthen the group in queries ?
Also you need an index on the second PK, not the first of the PK or AK compound of the two PK.
For me the best table will be:
CREATE TABLE PersonGroup
(
PersonId Int NOT NULL REFERENCES Person (PersonId),
GroupId Int NOT NULL REFERENCES Group (GroupId),
CONSTRAINT PK_PersonSgroup PRIMARY KEY (PersonId, GroupId)
);
CREATE INDEX X_PersonGroup_FK_Group (GroupId);

Did I write this query correctly?

I'm given the question
My solution is
USE Finances
CREATE TABLE Account
(AccountID varchar(25) NOT NULL PRIMARY KEY,
AccountName varchar(50) NOT NULL,
AccountAddress varchar(30) NULL,
AccountCity varchar(25) NULL,
AccountState char(2) NULL,
AccountZip varchar(10) NULL,
AccountPhone varchar(14) NULL)
CREATE TABLE Transactions
(TransactionID INT NOT NULL PRIMARY KEY IDENTITY,
AccountID varchar(25) REFERENCES Account (AccountID),
TransactionDate smalldatetime NOT NULL,
TransactionAmount money NOT NULL)
CREATE TABLE Register
(RegisterID INT NOT NULL PRIMARY KEY IDENTITY,
TransactionID INT NOT NULL REFERENCES Transactions (TransactionID));
Part of the reason I'm confused is because I don't completely understand the primary/foreign key relationship. Like I look at the question and say, ok the registerID will be the single/unique ID to seperate every account from each other. But I see that there's a TranasctionID in the same table. And that TransactionID is a foreign key to the TransactionID in the transaction table. So does that mean whenever a new tranasctionID is added there is a corresponding RegisterID. Like whats the point of the Register ID?? And did I write this query correctly?
The only issue in you script is your column "AccountID" in table "Transactions" is creating with allowing NULL and "TransactionAmount" is NOT NULL where as it should allow NULL. Other wise I found the tables are creating with appropriate type and relation as instructed.
Regarding your confusion, I am confused too thinking about the purpose of table "Register". As per instruction, yes it will create a new row every time a new transaction take place. As registerId is a PK, with each transaction a new PK will generate. But the question is why a new RegisterId is required for each TransactionID? If RegisterId is referring to other table for a transaction details, it can be easily use the TransactionID directly as both TransactionID and RegisterId are unique (PK).

Error creating FK Constraint: There are no primary or candidate keys in the referenced table 'Period' that match the referencing column

Majority of the tables in my database consist of composite primary keys due to the locations being different on the original platform but the identities are only unique at the given location. I have a Period table for the start and end dates of our fiscal year separated by the FiscalYear and PeriodID. PeriodID is repeating 1-12 so the primary key for this table is both the FiscalYear and PeriodID
FiscalYear INT NOT NULL,
PeriodID TINYINT NOT NULL,
PeriodStart DATE NOT NULL,
PeriodEnd DATE NOT NULL,
PeriodWeeks TINYINT NOT NULL,
QuarterID TINYINT NOT NULL,
DateManipulate DATE NOT NULL,
CONSTRAINT [PK_Period] PRIMARY KEY (PeriodID, FiscalYear)
I also have a Clinic.Dates table that uses the same FiscalYear and PeriodID but has data unique to each location. I have these separated so I don't have 40 instances of the same FiscalYear and PeriodID with the date ranges being repeated.
ClinicID INT NOT NULL CONSTRAINT [FK_ClinicDates] FOREIGN KEY REFERENCES Clinic.Master(ClinicID),
FiscalYear INT NOT NULL,
PeriodID TINYINT NOT NULL,
PeriodDays INT NOT NULL,
CONSTRAINT [PK_Dates] PRIMARY KEY (ClinicID, PeriodID, FiscalYear)
The issue I am having is creating a foreign key constraint between these tables due to the columns not being unique on their own.
ALTER TABLE Clinic.Dates ADD
CONSTRAINT FK_PeriodDates FOREIGN KEY(FiscalYear, PeriodID) REFERENCES Clinic.Period(FiscalYear, PeriodID)
GO
The error I'm getting is:
There are no primary or candidate keys in the referenced table 'Clinic.Period' that match the referencing column list in the foreign key 'FK_PeriodDates'.
My question: is there another way around this? The primary key exists in the Clinic.Period table but isn't recognized when attempting to make this FK constraint.
UPDATE: Here are a couple of data examples for both of the tables for a better perspective.
Period Table:
Clinic.Dates Table:
You have the reference backwards. It should go from the Clinic.Periods table to Clinic.Dates:
ALTER TABLE Clinic.Periods ADD
CONSTRAINT FK_PeriodDates FOREIGN KEY(FiscalYear, PeriodID) REFERENCES Clinic.Dates(FiscalYear, PeriodID)
GO

two digit year as primary key in sql server

I have a table with these columns:
ID int,
d date
Now what I need is to define the primary key in such a way that ID would be unique for each year; meaning that there can not be two same IDs in 2004, but it is possible to have two same IDs in two different years.
Like:
insert into myTable values(1, '1-1-2004'), (1, '1-1-2005')
but not like:
insert into myTable values(1, '3-1-2005'), (1, '1-1-2005')
I tried this:
primary key(ID, datepart(YY, d))
but I get syntax error.
One way of doing this, if you can alter the table structure, is to add a persisted computed column for the year part, and then add a primary key for (id, computer_col), like this:
CREATE TABLE myTable (
id INT NOT NULL,
d DATE NOT NULL,
y AS DATEPART(YEAR,d) PERSISTED NOT NULL,
PRIMARY KEY(id,y)
)
I'm not saying this is a good solution in any way, but it should work. Using a trigger on insert or a check constraint might be better.
Using your test data this will allow the first insert statement, but disallow the second as it violates the primary key constraint.

Foreign key to part of primary key's table

I have a database with this tables Conversion and Client I want to create relation between this tables so ID_Send in Conversion Reference to ID in Client and ID_Receive in Conversion Reference to ID in Client
create table Conversion(ID_Send int ,
ID_Receive int ,
[Time] datetime,
[Message] varchar(2048),
primary key(ID_Send,ID_Receive,[Time])
)
create table Client (ID int IDENTITY(1,1) primary key,
[First name] varchar(500) not null,
[Last Name]varchar(500) not null,
[Birth day] datetime,
Gender bit not null,
Country varchar(200)not null,
City varchar(200) ,
[Language] varchar(200)not null,
[Chat name] varchar(500)not null ,
[Password] varchar (500)not null,
--foreign key(ID) REFERENCES Conversion (ID_Send)--there is an error
)
Motazz, there can be only one Primary key in a table like you have in the Client table. to get rid of the error:
1st create the Client table,
2nd replace the code for Conversion with:
create table Conversion(ID_Send int FOREIGN KEY REFERENCES Client(ID),
ID_Receive int FOREIGN KEY REFERENCES Client(ID),
[Time] datetime,
[Message] varchar(2048),
primary key(ID_Send,ID_Receive,[Time])
)
If you have a compound primary key (made up of mulitple columns), all your foreign keys also must use all columns of the PK to reference that table.
After all : how else would you be able to make a clear, deterministic reference from a child table to the parent? Only if you use the columns that uniquely identify one row in the parent table does this work.
The only workaround would be to put a UNIQUE index on the ID_Send and ID_Receive columns in your parent table and then reference that unique index.
But then the question is: if those values are unique - why isn't one of those columns alone your primary key??

Resources