Transact-SQL: Getting ID of Lookup Value if Data isn't Related - sql

I have 3 tables and two are related (Name and Gender):
Staging(id, name, gender)
Name(id, name genderID)
Gender(id, gender)
The data has been "dumped" into Staging(id, name, gender) in a denormalized fashion and now I'm trying to normalize the data.
I need to be able to use t-sql to do the following
Insert the name from the Staging table into the Name table
Get the id from the Gender table and insert into the Name table as a foreign key
The problem is the Gender and Name tables aren't related to Staging so I'm trying to understand the logic of how this transaction should work.
My assumption was that I needed to somehow to an INSERT INTO SELECT with some type of subquery, but I'm just at a lost. Thanks.

Yes, you need INSERT INTO...SELECT. Join table staging with Gender via column gender so you can get the ID.
INSERT INTO Name (ID, Name, GenderID)
SELECT s.id, s.name, g.id
FROM Staging s
INNER JOIN Gender g
ON s.gender = g.gender

Related

Inserting data into a table(mutliple columns) which has primary key from another data which has data except primary key

I have a table that has 3 columns ID(Primary Key), Name, City.
I need to import data from another table that has only Name and City.
I can write insert into table 1(Name, City) select Name, City from table2.
But then I need ID in table 1 which needs to be inserted using a sequence.
I tried this:
insert into table1(ID, Name,City) values(seq.nextval, select distinct name, city from table2). But I am receiving an error saying an insufficient number of values.
I am trying it in SQL Oracle. Can someone please help me with this?
You are mixing the insert ... values and insert ... select syntax.
You edited your question to include distinct, implying you have duplicate name/city pairs that you want to suppress; but neither version gets the error you reported. If you don't have duplicates then you can just do:
insert into table1(ID, Name,City)
select seq.nextval, name, city from table2;
If you do have duplicates then you can't just add the distinct keyword, but you can use a subquery:
insert into table1 (id, name, city)
select seq.nextval, name, city
from (
select distinct name, city
from table2
);
db<>fiddle
You could also set the ID via a trigger. If you we're on a recent version you could use an identity column instead - but you tagged the question with Oracle 11g, where those are not available.

Conditionally insert multiple data rows into multiple Postgres tables

I have multiple rows of data. And this is just some made up data in order to make an easy example.
The data has name, age and location.
I want to insert the data into two tables, persons and locations, where locations has a FK to persons.
Nothing should be inserted if there already is a person with that name, or if the age is below 18.
I need to use COPY (in my real world example I'm using NPQSQL for .NET and I think that's the fastest way of inserting a lot of data).
So I'll do the following in a transaction (not 100% sure on the syntax, not on my computer right now):
-- Create a temp table
DROP TABLE IF EXISTS tmp_x;
CREATE TEMPORARY TABLE tmp_x
(
name TEXT,
age INTEGER,
location TEXT
);
-- Read the data into the temp table
COPY tmp_x (name, age) FROM STDIN (FORMAT BINARY);
-- Conditionally insert the data into persons
WITH insertedPersons AS (
INSERT INTO persons (name, age)
SELECT name, age
FROM tmp_x tmp
LEFT JOIN persons p ON p.name = tmp.name
WHERE
p IS NULL
AND tmp.age >= 18
RETURNING id, name
),
-- Use the generated ids to insert the relational data into locations
WITH insertedLocations AS (
INSERT INTO locations (personid, location)
SELECT ip.id, tmp.location
FROM tmp_x tmp
INNER JOIN insertedPersons ip ON ip.name = tmp.name
),
DROP TABLE tmp_x;
Is there a better/easier/more efficient way to do this?
Is there a better way to "link" the inserts instead of INNER JOIN insertedPersons ip ON ip.name = tmp.name. What if name wasn't unique? Can I update tmp_x with the new person ids and use that?

Copying data from one table to another different column names

I'm having an issue copying one table's data to another. I have around 100 or so individual tables that have generally the same field names but not always. I need to be able to copy and map the fields. example: source table is BROWARD and has column names broward_ID, name, dob, address (the list goes on). The temp table I want to copy it to has ID, name, dob, address etc.
I'd like to map the fields like broward_ID = ID, name = name, etc. But many of the other tables are different in column name, so I will have to write a query for each one. Once I figure out the first on, I can do the rest. Also the column in both tables are not in order either..thanks in advance for the TSQL...
With tables:
BROWARD (broward_ID, name, dob, address) /*source*/
TEMP (ID, name, address,dob) /*target*/
If you want to copy information from BROWARD to TEMP then:
INSERT INTO TEMP SELECT broward_ID,NAME,ADDRESS,DOB FROM BROWARD --check that the order of columns in select represents the order in the target table
If you want only copy values of broward_ID and name then:
INSERT INTO TEMP(ID, name) SELECT broward_ID,NAME FROM BROWARD
Your question will resolve using update
Let's consider we have two different table
Table A
Id Name
1 abc
2 cde
Table B
Id Name
1
2
In above case want to insert Table A Name column data into Table B Name column
update B inner join on B.Id = A.Id set B.Name = A.Name where ...

Performing multiple inserts for a single row in a query

I have a table containing data that i need to migrate into another table with a linking table. This is a one time migration as part of an upgrade.
I have a company table that contains records relating to a company and a contact person.
I want to migrate the contact details into another table and link the new person with a linking table
Consider I have this table which is already populated
tblCompany
CompanyId
CompanyName
RegNo
ContactForename
ContactSurname
And i want to migrate the contact person data to
tblPerson
PersonID (identitycolumn)
Forename
Surname
and use the identity column resulting and insert it into the linking table
tblCompanyPerson
CompanyId
PersonId
I've tried a few different ways to approach this using cursors and output variables into a temp table but none seem right to me (or give me the solution...)
The closest i have got is to have a companyID on tblPerson and insert companyId into it and output the new personId and the companyId into a temp table. Then loop through the temp table to create the tblCompanyContact.
example
declare #companycontact TABLE (companyId int, PersonId int)
insert into tblPerson
(Forename,
Surname,
CompanyID)
output inserted.CompanyID, INSERTED.PersonID into #companycontact
select
ContactPersonForeName,
ContactPersonSurename,
CompanyID
from tblCompany c
insert into tblCompanyPerson
(CompanyID,
PersonID)
select c.companyId, PersonId from #companycontact c
Background
Im using MS SQL Server 2008 R2
The tblPerson is already populated with hundreds of thousands of
records.
There is a 'trick' using MERGE statement to achieve mapping between newly inserted and source values:
MERGE tblPerson trgt
USING tblCompany src ON 1=0
WHEN NOT MATCHED
THEN INSERT
(Forename, Surename)
VALUES (src.ContactPersonForeName, src.ContactPersonSurename)
OUTPUT src.CompanyID, INSERTED.PersonID
INTO tblCompanyPerson (CompanyId, PersonID);
That 1=0 condition is to always get everything from source. You might want to replace it or even whole source with some sub-query to actually check whatever you already have same person mapped.
EDIT: Here is some reading about using MERGE and OUTPUT
Because I don't know what SQL you are using its difficult to decide if this is correct. i also don't know if you already tried this but it's the best idea i have:
insert into tblPerson
(Forename, Surename)
Select ContactForename, ContactPersonSurename
from tblCompany
insert into tblCompanyPerson
(CompanyID, PersonID)
select CompanyId, PersonID
from tblPerson, tblCompany
where ContactForename = Forename and ContactPersonSurename = Surename
Sarajog

Underlying rows in Group By

I have a table with a certain number of columns and a primary key column (suppose OriginalKey). I perform a GROUP BY on a certain sub-set of those columns and store them in a temporary table with primary key (suppose GroupKey). At a later stage, I may need to get more details about one or more of those groupings (which can be found in the temporary table) i.e. I need to know which were the rows from the original table that formed that group. Simply put, I need to know the mappings between GroupKey and OriginalKey. What's the best way to do this? Thanks in advance.
Example:
Table Student(
StudentID INT PRIMARY KEY,
Level INT, --Grade/Class/Level depending on which country you are from)
HomeTown TEXT,
Gender CHAR)
INSERT INTO TempTable SELECT HomeTown, Gender, COUNT(*) AS NumStudents FROM Student GROUP BY HomeTown, Gender
On a later date, I would like to find out details about all towns that have more than 50 male students and know details of every one of them.
How about joining the 2 tables using the GroupKey, which, you say, are the same?
Or how about doing:
select * from OriginalTable where
GroupKey in (select GroupKey from my_temp_table)
You'd need to store the fields you grouped on in your temporary table, so you can join back to the original table. e.g. if you grouped on fieldA, fieldB, and fieldC, you'd need something like:
select original.id
from original
inner join temptable on
temptable.fieldA = original.fieldA and
temptable.fieldB = original.fieldB and
temptable.fieldC = original.fieldC