SQL insert into related tables - sql

This seems to me to be the kind of issue that would crop up all the time with SQL/database development, but then I'm new to all this, so forgive my ignorance.
I have 2 tables:
CREATE TABLE [dbo].[Tracks](
[TrackStringId] [bigint] NOT NULL,
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[Time] [datetime] NOT NULL,
CONSTRAINT [PK_Tracks] PRIMARY KEY CLUSTERED
(
[Id] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Tracks] CHECK CONSTRAINT [FK_Tracks_AudioStreams]
GO
ALTER TABLE [dbo].[Tracks] WITH CHECK ADD CONSTRAINT
[FK_Tracks_TrackStrings] FOREIGN KEY([TrackStringId])
REFERENCES [dbo].[TrackStrings] ([Id])
GO
ALTER TABLE [dbo].[Tracks] CHECK CONSTRAINT [FK_Tracks_TrackStrings]
GO
and
CREATE TABLE [dbo].[TrackStrings](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[String] [nvarchar](512) NOT NULL,
CONSTRAINT [PK_Strings] PRIMARY KEY CLUSTERED
(
[Id] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
I want to insert a new entry into the tracks table. This will also involve inserting a new entry in the trackstrings table, and ensuring that the foreign key column trackstringid in tracks points to the new entry in trackstrings. What is the most efficient means of achieving this?

First, insert into TrackStrings, omitting the primary key column from the column list. This invokes its IDENTITY column which generates a value automatically.
INSERT INTO [dbo].[TrackStrings] ([String])
VALUES ('some string');
Second, insert into Tracks and specify as its TrackStringId the function SCOPE_IDENTITY(), which returns the most recent value generated by an IDENTITY column in your current scope.
INSERT INTO [dbo].[Tracks] ([TrackStringId], [Time])
VALUES (SCOPE_IDENTITY(), CURRENT_TIMESTAMP());

If you are using SQL Server 2005 or later and are inserting a lot of records in a single INSERT, you can look into OUTPUT or OUTPUT INTO options here to use the identities from the first insert in the second without haveing to "re-find" the rows to get all the IDENTITY values.

First insert into the primary table.
INSERT INTO trackstrings VALUES('myvalue')
Next get the identity. This method depends on whether you're are doing it all in 1 statement or a stored procedure or some other method. I will assume 1 statement so I'll just insert with the identity special variable.
INSERT INTO tracks VALUES( ##IDENTITY, getdate() )
Something like that should do it depending on your exact scenario. The key is the ##IDENTITY variable. It holds the last inserted identity value for the connection you are using. It is not table specific, it is simply the most recent identity inserted during the connections lifespan.

Related

Populating GUID column with NEWID() in an INSERT INTO SELECT FROM statement is throwing an error (NULL) value

I am trying to populate Table1 with values from Table2 if they do not already exist in Table1.
Table1 has a UNIQUEIDENTIFIER constraint and has a default value of NEWID() specified.
I was using a SELECT DISTINCT statement to get the results from Table2 and eventually just created a view to do that for me. I'll state up front that there are no duplicate values in Table2View.
I've also tried to drop the results of the SELECT statement to a temp table and populating a GUID on the temp table using NEWID() and pulling the values over from there. No matter what I've tried so far produces the same error.
Violation of UNIQUE KEY constraint 'constraintname'. Cannot insert duplicate key in object 'dbo.table1'. The duplicate key value is NULL.
Here is the CREATE TO on Table1:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Table1]
(
[UID] [uniqueidentifier] ROWGUIDCOL NOT NULL,
[DataID] [varchar](10) NULL,
[DataName] [varchar](100) NULL,
[DataType] [varchar](10) NULL,
[DateLastPopulated] [date] NULL,
[LastAmount] [bigint] NULL,
[DateRecordCreated] [datetime] NULL,
[DateLastModified] [datetime] NULL,
PRIMARY KEY CLUSTERED ([UID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
UNIQUE NONCLUSTERED ([DataID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Table1]
ADD CONSTRAINT [DF_Table1_UID] DEFAULT (NEWID()) FOR [UID]
GO
ALTER TABLE [dbo].[Table1]
ADD CONSTRAINT [CNST_Table1_CreateDate] DEFAULT (GETDATE()) FOR [DateRecordCreated]
GO
ALTER TABLE [dbo].[Table1] WITH CHECK
ADD CONSTRAINT [FK_Table1_ForeignTable]
FOREIGN KEY([ForeignID]) REFERENCES [dbo].[ForeignTable] ([ForeignID])
GO
ALTER TABLE [dbo].[Table1] CHECK CONSTRAINT [FK_Table1_ForeignTable]
GO
Here is the query I am running to populate the table:
INSERT INTO [dbo].[Table1] ([UID], DataName, DateLastPopulated, LastAmount)
SELECT NEWID(), B.DataName, B.DateLastPopulated, B.LastAmount
FROM [dbo].[Table2_View] B
LEFT JOIN [dbo].[Table1] A ON B.DataName = A.DataName
WHERE A.DataName IS NULL
I have ran the SELECT statement from the INSERT by itself and there are no NULL values and no duplicate values. The query runs fine and NEWID() populates a GUID.
However, adding the SELECT statement to the INSERT INTO produces the error.
Any help at all would be greatly appreciated. I've googled this issue to the point of insanity.
A unique column in SQL Server only allows one NULL value. You seem to have multiple NULL values, and that is the problem.
You can fix this by replacing the constraint with a filtered index:
create unique index unq_table1_dataid
on (dataid)
where dataid is not null;
I do not remember if the standard actually specifies how NULL values are handled with unique constraints. Databases do it both ways. SQL itself is inconsistent . . . NULL = NULL is treated as false when filtering, but NULL = NULL when doing aggregation.
Well coincidentally, I was able to solve the problem. I removed the Primary Key from the GUID column and the query ran just fine after that. It seems that it was trying to commit the NULL value before committing the full record. Doing a SELECT * on the table after running the query shows that there were no NULL values inserted. Good grief!

Microsoft SQL Server 2014: Incorrect Generated Script Ordering when Export Self-Referenced Table to SQL

I have a question regarding the data script generation tools in SQL Server.
I have a table which contains a column parentId referencing the id of its parent. In other words, this table is self-referencing. When I generate data script for this table (using Task -> Generate Scripts), the SQL generated in incorrect order.
It seems that the generated script is in alphabetical order of column id but ignoring the self-referenced foreign key.
Schema for the table
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[MyTable]
(
[id] [nvarchar](50) NOT NULL,
[parentId] [nvarchar](50) NULL
CONSTRAINT [PK_MyTable]
PRIMARY KEY CLUSTERED([id] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[MyTable] WITH CHECK
ADD CONSTRAINT [FK_MyTable_MyTable]
FOREIGN KEY ([parentId]) REFERENCES [dbo].[MyTable] ([id])
GO
ALTER TABLE [dbo].[MyTable] CHECK CONSTRAINT [FK_MyTable_MyTable]
GO
Incorrectly generated data script
INSERT [dbo].[MyTable] ([id], [parentId]) VALUES (N'AAA', N'BBB')
INSERT [dbo].[MyTable] ([id], [parentId]) VALUES (N'BBB', NULL)
I want to generate data script in correct execution order i.e. those data script containing important id must go first before their id can be used as the parentId in other data script. I really find no way to configure SQL Server and I find no solution despite searching through the net for a week.
Please help!!

How to create two or more Unique Columns in SQL Azure?

I want to select two columns in my table and make them unique but I don't know how to do it in SQL Azure database. As you can see in the image below, it doesn't show any option to modify the table properties, so everything is done using sql queries:
Here is the generated script of the table:
USE [mydbase]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[clientaccess](
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[ModuleName] [nvarchar](50) NOT NULL,
[ClientAuthenticationId] [bigint] NOT NULL,
[HasAccess] [bit] NOT NULL,
CONSTRAINT [PK_clientaccess_ID] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
GO
ALTER TABLE [dbo].[clientaccess] WITH CHECK ADD CONSTRAINT [CAI_caID] FOREIGN KEY([ClientAuthenticationId])
REFERENCES [dbo].[clientauthentication] ([ID])
GO
ALTER TABLE [dbo].[clientaccess] CHECK CONSTRAINT [CAI_caID]
GO
This is the preview where I encountered the problem, it contains duplicate records:
Hope someone understand my explanation.
Sometimes GUIS have limitations (or not but you haven't discovered yet how all functionalities work). You can always add a unique constraint with ALTER TABLE:
ALTER TABLE [dbo].[clientaccess]
ADD CONSTRAINT Module_Client_UQ --- choose a name
UNIQUE (ModuleName, ClientAuthenticationId) ;

Should I use the inserted table in this trigger to set a default value for a nullable foreign key?

I have a table with a nullable FK field. I made it nullablle to avoid changing the loader.
In order to achieve (Advertisers)* 1(Currencies), I wrote a simple trigger:
ALTER TRIGGER InsertedAdvertisersDefaultCurrency
ON dbo.Advertisers
FOR INSERT
AS
UPDATE Advertisers
SET Currency_Id=(SELECT TOP 1 Id FROM Currencies WHERE Name='USD')
WHERE Currency_Id=NULL
My question is basically about how I am checking the whole table for null rows on every insert.
I feel like I should be using the inserted table (?)
Here's the table:
CREATE TABLE [dbo].[Advertisers](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](max) NOT NULL,
[Currency_Id] [int] NULL,
CONSTRAINT [PK_Advertisers] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Advertisers] WITH CHECK ADD CONSTRAINT [FK_CurrencyAdvertiser1] FOREIGN KEY([Currency_Id])
REFERENCES [dbo].[Currencies] ([Id])
GO
ALTER TABLE [dbo].[Advertisers] CHECK CONSTRAINT [FK_CurrencyAdvertiser1]
GO
Yes, you should just update the insertd records:
UPDATE Advertisers
SET Currency_Id=(SELECT TOP 1 Id FROM Currencies WHERE Name='USD')
WHERE Id in (select Id from inserted)
Or you may use a default value in that field
ALTER TABLE [dbo].[Advertisers] ADD CONSTRAINT [DF_Advertisers_Currency_Id] DEFAULT ((101)) FOR [Currency_Id]
GO
Where 101 is the USD id

How do you add Foreign Key Relationships?

I'm working with an existing SQL 2005 database that was not implemented with FK relationships between tables. I tried to add the relationships with a database diagram and my application immediately blew up trying to edit or insert any data that is tied to the new FK.
dbo.person [person_id | firstname | lastname | dateofbirth]
dbo.campaign [campaign_id | campaign_description]
dbo.disposition [disposition_id | disposition_description]
dbo.person_campaigns [person_campaign_id | person_id | campaign_id | disposition_id]
The person_campaigns table is where a person, campaign, and disposition are tied together. Can you please provide the appropriate SQL syntax for adding the proper FK relationships between these entities?
EDIT
CREATE TABLE [dbo].[person_campaigns](
[person_campaigns_id] [int] IDENTITY(1,1) NOT NULL,
[person_id] [int] NOT NULL,
[d_campaign_id] [int] NOT NULL,
[d_physician_disposition_id] [int] NULL,
CONSTRAINT [PK_person_campaigns] PRIMARY KEY CLUSTERED
(
[person_campaigns_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[d_campaign](
[d_campaign_id] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](50) NULL,
[year] [int] NULL,
[isactive] [bit] NOT NULL,
CONSTRAINT [PK_d_campaign] PRIMARY KEY CLUSTERED
(
[d_campaign_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[d_campaign] ADD CONSTRAINT [DF_d_campaign_isactive] DEFAULT ((1)) FOR [isactive]
GO
CREATE TABLE [dbo].[d_disposition](
[d_disposition_id] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](50) NULL,
[isactive] [bit] NOT NULL,
CONSTRAINT [PK_d_disposition] PRIMARY KEY CLUSTERED
(
[d_disposition_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[d_disposition] ADD CONSTRAINT [DF_d_disposition_isactive] DEFAULT ((1)) FOR [isactive]
GO
CREATE TABLE [dbo].[person](
[person_id] [int] IDENTITY(1,1) NOT NULL,
[firstname] [varchar](30) NULL,
[lastname] [varchar](30) NULL,
[dateofbirth] [datetime] NULL
CONSTRAINT [PK__person__0BC6C43E] PRIMARY KEY CLUSTERED
(
[person_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
the easiest way to do it is through the database diagram editor; do them one at a time and save the diagram to affect the tables after each connection is made. If it "blows up" it is most likely because the tables contain foreign-key values that do not exist; you'll have to clean these up first.
If you have to add them after the table is created the syntax is
create table person (person_id int primary key
,firstname varchar(10)
, lastname varchar(10)
, dateofbirth varchar(10))
create table campaign (campaign_id int primary key
, campaign_description varchar(10))
create table disposition (disposition_id int primary key
,disposition_description varchar(10))
create table person_campaigns(person_campaign_id int
,person_id int, campaign_id int ,disposition_id int)
go
alter table person_campaigns add Constraint
fk_person_campaigns_person_id
Foreign Key (person_id) References person(person_id)
GO
alter table person_campaigns add Constraint
fk_person_campaigns_campaign_id
Foreign Key (campaign_id) References campaign(campaign_id)
GO
alter table person_campaigns add Constraint
fk_person_campaigns_disposition_id
Foreign Key (disposition_id) References disposition(disposition_id)
GO
Suppose I had two tables that should have had a foreign key but did not. The first thing to do is check to see if there will be a data problem if I set a foreign key.
something like the below code would get you the records in the child table that do not have a match in the parent table.
select t2.FKField, t2.PKfield from table2 t2
left join Table1 t1 on t2.fkfield = t1.pkfield
where t1.pkfield is null
Once you can see what is wrong with the existing data, then you need to create a way to fix it. The fix will vary depending on what data you have that has no relationship to the Parent table and what the tables represent. Suppose your parent table contained a VIN number for automobiles as the PK. If your child table contains the cars that were worked on by the shop, you would want to fix the issue by adding the nonexisting VINS to the primary table becasue you wouldn't want to lose the history of what was worked on. There are other structures where you might want to simply delete the records that don't match in child table because they are meaningless. In other circumstances you might want to update those records to some default value (perhaps a customer in the customer table called unknown). In still other circumstances, you might need to go to audit tables or backups to find the value of the PK that was deleted without the associated child records being deleted. The actual way to fix this problem is highly dependent on what the data is used for and how important it is to retain all historical records. Since you should never delete any record that might be related to a financial transaction for legal (and accounting) reasons, you need to be most careful with those.
After fixing all the data, then you run the code to create the FK constraint.
Since I don't have SQL Server on this PC and I don't memorize the syntax, the easiest thing to do is to create two new test tables, create TableA with an ID field, TableB with a field that is a FK of TableA.ID, and then script out TableB to see the ADD CONSTRAINT syntax. Do this using SQL Server Management Studio via a database diagram.
However, if you were able to successfully create the FKs in a data diagram, and you only can't add or update records, I believe something else is wrong. Script out the person_campaigns table and post the code.