How do I select insert into select a table which already has values in the primary key column without adding new rows? - sql

I'm working on a database for my school project in which I have to produce a functional database by normalizing sample tables given to us.
One table I'm having trouble with is itineraries. I produce 3 tables from the normalization which are "Destinations", "Itineraries" and "Itinerary_Destinations".
The code for Destinations is:
create table Destinations
(
DestinationID varchar(5) primary key,
Name varchar(45)
);
The code for Itineraries is:
create table Itineraries
(
ItineraryID varchar(5),
Name varchar(45)
);
The code for the last table is:
create table Itinerary_Destinations
(
DI varchar(5) primary key,
ItineraryID varchar(5) foreign key references Itineraries(ItineraryID),
Itinerary_Name varchar(45),
DestinationID varchar(5) foreign key references Destinations(DestinationID),
Destination_Name varchar(45)
);
Data has already been inserted into all 3 tables with the exception of 'Destination_Name' and 'Itinerary_Name' columns. The code I'm attempting to use is returning as error. The code is shown below.
insert into Itinerary_Destinations (Itinerary_name)
select Name from Itineraries where
Itineraries.ItineraryID = ItineraryID;
The error it returns is
Msg 515, Level 16, State 2, Line 1 Cannot insert the value NULL into
column 'DI', table 'DDDAssignment.dbo.Itinerary_Destinations'; column
does not allow nulls. INSERT fails. The statement has been terminated.
Is there a method to accomplish the task of inserting the Destination_Name and Itinerary_Name without creating new records that require primary keys?
Or should I do it manually?

If you want to modify records which already exist, then you should be using an UPDATE rather than an INSERT:
UPDATE a
SET Itinerary_name = b.Name
FROM Itinerary_Destinations a
INNER JOIN Itinerary_name b
ON a.ItineraryID = b.ItineraryID;
But, if you do have some data which is not already logically associated with the Itinerary_Destinations table, then using an insert is appropriate.

use coalesce funtion in case null it will insert blank string, as your column does not allow null value thats why you got that error in your query
insert into Itinerary_Destinations (Itinerary_name)
select coalesce(Name,' ') from Itineraries where
Itineraries.ItineraryID = ItineraryID;

Related

Is it possible to store a query in a variable and use that variable in Insert query? "#countrid =SELECT id FROM COUNTRIES WHERE description = 'asdf';"

So I've been going through SQL migrations to insert data in a SEQUENTIAL manner specifically from parent to child.
I've inserted data in the parent table. Now I've to store the primary key value of that
specific row (WHERE condition is defined in query for reference " where description = '1234'") in a variable.
And while inserting data to the child table I've to use that primary key value stored in a variable in place of a foreign key column("country_code_id") of the child table.
I'm using Postgresql
CREATE TABLE Countries
(
id SERIAL,
description VARCHAR(100),
CONSTRAINT coutry_pkey PRIMARY KEY (id)
);
CREATE TABLE Cities
(
country_code_id int ,
city_id int,
description VARCHAR(100),
CONSTRAINT cities_pkey PRIMARY KEY (city_id),
CONSTRAINT fk_cities_countries FOREIGN KEY (country_code_id) REFERENCES Countries (id)
);
INSERT INTO COUNTRIES (description) VALUES('asdf');
#countrid = SELECT id FROM COUNTRIES WHERE description = 'asdf';
INSERT INTO cities VALUES (countrid, 1 , 'abc');
SQL does not have variables. The normal way to do this is to use INSERT ... RETURNING:
INSERT INTO countries (description) VALUES ('1234')
RETURNING id;
This will return the automatically generated primary key. You store that in a variable on the client side and run a second statement:
INSERT INTO cities (country_code_id, city_id, description)
VALUES (4711, 1, 'abc');
where 4711 is the value returned from the first statement. To avoid hard-coding the value, you can use a prepared statement, which also will boost performance.
An alternative, more complicated, solution is to run both statements in a single statement using a common table expression:
WITH country_ids AS (
INSERT INTO countries (description) VALUES ('1234')
RETURNING id
INSERT INTO (country_code_id, city_id, description)
SELECT id, 1, 'abc'
FROM country_ids;

Insert into table1 using data from staging_table1 and table2, while using staging_table1 to get the data from table2

Goal: Insert all data into a table from staging table. Each piece of data in the staging table has 2 names which can be found in a separate table. By using the 2 two names, I want to find their respective IDs and insert them into the foreign keys of the main table.
Question: How do I insert the data from a staging table into a table while using data from the staging to query IDs from a separate table?
Example tables:
TABLE location:
id int PRIMARY KEY,
location varchar(255) NOT NULL,
person_oneID int FOREIGN KEY REFERENCES people(person_id),
person_twoID int FOREIGN KEY REFERENCES people(person_id)
TABLE staging_location:
id int PRIMARY KEY,
location varchar(255) NOT NULL,
p1_full_name varchar(255) NOT NULL,
p2_full_name varchar(255) NOT NULL
TABLE people:
person_id int PRIMARY KEY,
first_name varchar(255) NOT NULL,
last_name varchar(255) NOT NULL,
full_name varchar(255) NOT NULL,
This question was the closest example to what I have been looking for. Though I haven't been able to get the query to work. Here is what I've tried:
INSERT INTO location(id,location,person_oneID,person_twoID)
SELECT (l.id,l.location,p1.person_oneID,p2.person_twoID)
FROM staging_location AS l
INNER JOIN people p1 ON p1.full_name = l.p1_full_name
INNER JOIN people p2 ON p2.full_name = l.p2_full_name
Additional info: I would like to do this in the same insert statement without using an update because of the number of locations being inserted. I'm using staging tables as a result of importing data from csv files. The csv file with people didn't have an ID field, so I created one for each person by following steps similar to the first answer from this question. Please let me know if any additional information is required or if I can find the answer to my question somewhere I haven't seen.
Use this code even though I do not know what your data structure is and a duplicate field may be inserted
INSERT INTO location(id,location,person_oneID,person_twoID)
SELECT (l.id,l.location,p1.person_id as person_oneID,p2.person_id as person_twoID)
FROM staging_location AS l
INNER JOIN people p1 ON p1.full_name = l.p1_full_name
INNER JOIN people p2 ON p2.full_name = l.p2_full_name

How to merge rows of one table to another while keeping foreign key constraints on autogenerated columns?

Here are two tables that I have, with Table B referencing Table A:
CREATE TABLE TableA
(
[Id_A] [bigint] IDENTITY(1,1) NOT NULL,
...
CONSTRAINT [PK_TableA_Id_A] PRIMARY KEY CLUSTERED
(
[Id_A] ASC
)
)
CREATE TABLE TableB
(
[Id_B] [bigint] IDENTITY(1,1) NOT NULL,
[RefId_A] [bigint] NOT NULL
...
CONSTRAINT [PK_TableB_Id_B] PRIMARY KEY CLUSTERED
(
[Id_B] ASC
)
)
ALTER TABLE [dbo].[TableB] WITH CHECK ADD CONSTRAINT [FK_Id_A] FOREIGN KEY([RefId_A])
REFERENCES [dbo].[TableA] ([Id_A])
These two tables are part of 2 databases.
Table A and Table B in database 1;
Table A and Table B in database 2.
I need to merge the rows of Table A from database 1 into Table A of database 2 and the rows of Table B from database 1 into Table B of database 2.
I used the SQL Data Import and Export Wizard , checked the Enable Identity Insert option but it fails:
An OLE DB record is available. Source: "Microsoft SQL Server Native
Client 11.0" Hresult: 0x80004005 Description: "Violation of PRIMARY
KEY constraint 'PK_TableB_Id_B'. Cannot insert duplicate key in object
'dbo.TableB'. The duplicate key value is (1).". (SQL Server Import and
Export Wizard)
Which seems to make sense. There are rows in Table B of database 1 that have the same auto-generated PK as rows of Table B in database 2.
QUESTION
In this scenario, how can I merge the tables content from database 1 to the tables of database 2 while maintaining the foreign key constraints?
You can try something like the following. In here we assume that you need to insert all records as new ones (and not compare if some already exist or not). I wrapped both operations in a transaction to ensure that both go OK or none at all.
BEGIN TRY
IF OBJECT_ID('tempdb..#IdentityRelationships') IS NOT NULL
DROP TABLE #IdentityRelationships
CREATE TABLE #IdentityRelationships (
OldIdentity INT,
NewIdentity INT)
BEGIN TRANSACTION
;WITH SourceData AS
(
SELECT
OldIdentity = A.Id_A,
OtherColumn = A.OtherColumn
FROM
Database1.Schema.TableA AS A
)
MERGE INTO
Database2.Schema.TableA AS T
USING
SourceData AS S ON 1 = 0 -- Will always execute the "WHEN NOT MATCHED" operation
WHEN NOT MATCHED THEN
INSERT (
OtherColumn)
VALUES (
S.OtherColumn)
OUTPUT
inserted.Id_A, -- "MERGE" clause can output non-inserted values
S.ID_A
INTO
#IdentityRelationships (
NewIdentity,
OldIdentity);
INSERT INTO Database2.Schema.TableB (
RefId_A,
OtherData)
SELECT
RefId_A = I.NewIdentity,
OtherData = T.OtherData
FROM
Database1.Schema.TableB AS T
INNER JOIN #IdentityRelationships AS I ON T.RefID_A = I.OldIdentity
COMMIT
END TRY
BEGIN CATCH
DECLARE #v_ErrorMessage VARCHAR(MAX) = CONVERT(VARCHAR(MAX), ERROR_MESSAGE())
IF ##TRANCOUNT > 0
ROLLBACK
RAISERROR (#v_ErrorMessage, 16, 1)
END CATCH
This is too long for a comment.
There is no simple way to do this. Your primary keys are identity columns that both start at "1", so the relationships are ambiguous.
You have two options:
A composite primary key, identifying the database source of the records.
A new primary key. You can preserve the existing primary key values from one database.
Your question doesn't provide enough information to say which is the better approach: "merge" is not clearly defined.
I might suggest that you just recreate all the tables. Insert all the rows from table A into a new table. Add a new identity primary key. Keep the original primary key and source.
Then bring the data from Table B into a new table, looking up the new primary key in the new Table A. At this point, the new Table B is finished, except for defining the primary key constraint.
Then drop the unnecessarily columns in the new table A.

How to use value generated by GENERATE_UNIQUE() function as foreign key?

I trying to implement the example from this manual Generating Unique Values in DB2 Universal Database but encountered the following problem.
I've two tables,
CREATE TABLE PC_LIST (
PC_ID CHAR(13) FOR BIT DATA NOT NULL,
PC_NAME VARCHAR(100) NOT NULL
PRIMARY KEY (ID)
);
And second table
CREATE TABLE PC_DATA (
ID CHAR(13) FOR BIT DATA NOT NULL,
PC_ID CHAR(13) FOR BIT DATA NOT NULL,
PC_NAME VARCHAR(100) NOT NULL
PRIMARY KEY (ID),
FOREIGN KEY (PC_ID) REFERENCES PC_LIST(PC_ID)
);
I add records to first table PC_LIST without any issues, and use inside INSERT query GENERATE_UNIQUE() function, everything works fine.
When I try to add a record to the second table and copy a value from PC_LIST.PC_ID as is I get an error Value "20150408131401000109000000 " is too long..
When I added a cast like following: CAST('20150408131401000109000000' AS CHAR(13) FOR BIT DATA) I get an error that The INSERT or UPDATE value of the FOREIGN KEY is not equal to any value of the parent key of the parent table.
What am I doing wrong?
Thank you.
UPDATE:
This code I use to insert data in PC_DATA
INSERT INTO PC_DATA
(
ID,
PC_ID,
PC_NAME
) VALUES (GENERATE_UNIQUE(), CAST('20150408131401000109000000' AS CHAR(13) FOR BIT DATA) ,'anatoly-pc');
Of course that PC_ID I've taken from PC_LIST table where it exists.

Foreign Key is null when insert using Stored Procedure

I've created a insert stored procedure with two tables like in the exapmle:
Table NameAge
CREATE TABLE [dbo].[Assignment3_NameAge]
(
userID int PRIMARY KEY IDENTITY(1,1),
Name varchar(255) NOT NULL,
Age int NOT NULL
)
Table Hobbies
CREATE TABLE [dbo].[Assignment3_Hobbies]
(
hobbiesID int Identity(1,1) Primary Key,
userID int Foreign Key references Assignment3_NameAge(userID),
hobbies varchar(255) NOT NULL,
)
Insert Stored Procedure
CREATE PROCEDURE [dbo].p_Assignment3Join_ins
#Name nvarchar(100),
#Age int,
#Hobbies nvarchar(100)
AS
INSERT INTO [TABLE].[dbo].[Assignment3_NameAge]
([Name]
,[Age])
VALUES (#Name,#Age)
INSERT INTO [TABLE].[dbo].[Assignment3_Hobbies]
([Hobbies])
VALUES (#Hobbies)
The problem is that when i run the stored procedure the table Hobbies has a null value for userid(the foreign key)
What am i doing wrong?
You should provide the key of the Assignment3_NameAge value you want to insert into Assignment3_Hobbies.
If you want the last inserted you can use SCOPE_IDENTITY() from SQL Server(if you're using SQL Server) or equivalent. It will give you the last inserted value from Assignment3_NameAge
I am guessing this is SQL Server based on the IDENTITY column. Correct?
The first insert creates a user, but there is no user ID being set on the insert of the hobby. You need to capture the identity value from the first insert to be used in the second insert. Have you gon over the system functions available?
You're not supplying a value for it, SQL won't automagically fill the value in for you even though you've created a Foreign Key relationship. It's your job to populate the tables.