How to use merge statement to split one staging tables into two for loading from Staging to RealtionalDB? - sql

I have following tables. I want to insert values into companyGroup and Comapany from test1 table. what would be better way CTE or Using Merge directly and how can i do that using tsql. Test1 is on database A and company and companygroup are on database B.
create table test1
(
companyID int identity
,CompanyName Varchar(50)
,[Group] Varchar(5)
)
INSERT INTO (CompanyName, [Group]) values ('Unknown', '0')
INSERT INTO (CompanyName, [Group]) values ('APPLE', 'IOS')
INSERT INTO (CompanyName, [Group]) values ('Google', 'Android')
INSERT INTO (CompanyName, [Group]) values ('Samsung', 'Android')
INSERT INTO (CompanyName, [Group]) values ('Lg', 'IOS')
create table CompanyGroup
(
Groupkey int identity (0,1) primary key
,GroupName varchar(5)
) ;
INSERT INTO (GroupName) VALUES ('Unknown')
create table Company
(
compnayKey int identity (0,1) primary key
,CompanyName Varchar(50)
,companyGroupKey int References CompanyGroup(GroupKey)
)
INSERT INTO (CompanyName,companyGroupKey) VALUES ('Unknown',0)
when I insert the values into company how can i convert group to int ? Any ideas? What would be Best TSQL for this load.

Try using this:
INSERT INTO CompanyGroup(GroupName)
SELECT [Group]
FROM test1
WHERE NOT EXISTS(SELECT 1
FROM CompanyGroup
WHERE GroupName = [Group]);
MERGE Company AS target
USING (SELECT t.CompanyName, g.Groupkey
FROM test1 AS t
LEFT JOIN CompanyGroup AS g ON t.[Group] = g.GroupName
) AS source
ON (target.CompanyName = source.CompanyName
AND target.companyGroupKey = source.Groupkey)
WHEN NOT MATCHED THEN
INSERT (CompanyName, companyGroupKey)
VALUES (source.CompanyName, source.Groupkey);

Related

Finding trouble in generating the list of all Students who belongs to the major named as “CS” but not to major named as “EE”

S_id int Primary Key,
S_name varchar(100),
Gpa float ,
Size_hs int
)
Create table Apply (
s_id int ,
C_name varchar(100),
Major varchar(10),
Decision varchar(2)
)
insert into Students values (123,'Amy',3.9,1000)
insert into Students values (234,'Bob',3.6,1500)
insert into Students values (345,'Craig',3.5,500)
insert into Students values (456,'Doug',3.9,1000)
insert into Students values (567,'Edward',2.9,2000)
insert into Students values (678,'Fay',3.8,200)
insert into Students values (789,'Gray',3.4,800)
insert into Students values (987,'Helen',3.7,800)
insert into Students values (876,'Irene',3.9,400)
insert into Students values (765,'Jay',2.9,1500)
insert into Students values (654,'Amy',3.9,1000)
insert into Students values (543,'Craig',3.4,2000)
insert into Apply values (123,'NJIT','CS','Y')
insert into Apply values (123,'NJIT','EE','N')
insert into Apply values (123,'Stoony Brook','CS','Y')
insert into Apply values (123,'Cornell','EE','Y')
insert into Apply values (234,'Stoony Brook','Bio','N')
insert into Apply values (345,'WPI','Bio-Eng','Y')
insert into Apply values (345,'Cornell','Bio-Eng','N')
insert into Apply values (345,'Cornell','CS','Y')
insert into Apply values (345,'Cornell','EE','N')
insert into Apply values (678,'NJIT','Hist','Y')
insert into Apply values (987,'NJIT','CS','Y')
insert into Apply values (987,'Stoony Brook','CS','Y')
insert into Apply values (876,'NJIT','Bio','N')
insert into Apply values (876,'WPI','Marine-Bio','Y')
insert into Apply values (876,'WPI','Hist','N')
insert into Apply values (765,'NJIT','Hist','Y')
insert into Apply values (765,'Cornell','Hist','N')
insert into Apply values (765,'Cornell','Psych','Y')
insert into Apply values (543,'WPI','CS','N')
Create table Students(
S_id int Primary Key,
S_name varchar(100),
Gpa float ,
Size_hs int
)
Create table Apply (
s_id int ,
C_name varchar(100),
Major varchar(10),
Decision varchar(2)
)
insert into Students values (123,'Amy',3.9,1000)
insert into Students values (234,'Bob',3.6,1500)
insert into Students values (345,'Craig',3.5,500)
insert into Students values (456,'Doug',3.9,1000)
insert into Students values (567,'Edward',2.9,2000)
insert into Students values (678,'Fay',3.8,200)
insert into Students values (789,'Gray',3.4,800)
insert into Students values (987,'Helen',3.7,800)
insert into Students values (876,'Irene',3.9,400)
insert into Students values (765,'Jay',2.9,1500)
insert into Students values (654,'Amy',3.9,1000)
insert into Students values (543,'Craig',3.4,2000)
insert into Apply values (123,'NJIT','CS','Y')
insert into Apply values (123,'NJIT','EE','N')
insert into Apply values (123,'Stoony Brook','CS','Y')
insert into Apply values (123,'Cornell','EE','Y')
insert into Apply values (234,'Stoony Brook','Bio','N')
insert into Apply values (345,'WPI','Bio-Eng','Y')
insert into Apply values (345,'Cornell','Bio-Eng','N')
insert into Apply values (345,'Cornell','CS','Y')
insert into Apply values (345,'Cornell','EE','N')
insert into Apply values (678,'NJIT','Hist','Y')
insert into Apply values (987,'NJIT','CS','Y')
insert into Apply values (987,'Stoony Brook','CS','Y')
insert into Apply values (876,'NJIT','Bio','N')
insert into Apply values (876,'WPI','Marine-Bio','Y')
insert into Apply values (876,'WPI','Hist','N')
insert into Apply values (765,'NJIT','Hist','Y')
insert into Apply values (765,'Cornell','Hist','N')
insert into Apply values (765,'Cornell','Psych','Y')
insert into Apply values (543,'WPI','CS','N')
Basically I have to find the list of students id who belongs to major named as 'Cs' but not to the major 'EE'. I tried it by myself but it is not working properly.
Here is the code below:
select * from students
where s_id in (
select s_id
from apply
where major='CS' and Major!='EE'
group by s_id
)```
I would use exists and not exists:
select s.*
from students s
where
exists (select 1 from applies a where a.s_id = s._id and a.major = 'CS')
and not exists (select 1 from applies a where a.s_id = s._id and a.major = 'EE')
With an index on applies(s_id, major), this should be an efficient option.
Another approach is to join, aggregate, and filter with a having clause. This requires listing the columns that you want to show in both the select and group by clauses:
select s.s_id, s.s_name
from students s
inner join applies a on a.s_id = s.s_id
where a.major in ('CS', 'EE')
group by s.s_id, s.s_name
having
max(case when a.major = 'CS' then 1 else 0 end) = 1
and max(case when a.major = 'EE' then 1 else 0 end) = 0
Note: apply is a reserved word in a number a databases (SQL Serer, Oracle, ...), hence not a good choice for a table name. I renamed it to applies in the queries.

How to query a table with 2 foreign keys?

I have three tables in my android app.
Table Animal Table Group TableGroup_Animal
idAnimal idGroup idAnimal
AnimalName groupName idGroup
I want to know how to do query in order to get all the animals inside a group. The query I made is this
select
Groups.groupName
from
Groups,
Animal,
tableGrupo_Animal
where
Animal.idanimal = tableGroup_Animal.fkanimal
and
Groups.idgrupo = tableGrupo_Animal.fkgrupo
group by
group.groupName
And also this(That only shows the first row)
select
*
from
Animal
INNER JOIN " + tableGroup + " ON Animal.idanimal = Group.idGroup
where
Group.groupName = ' " + groupName +
As I said I want to get all the animals inside a group, how can I do that? Thanks
I recreated your database in sqlite and tested this out. This SQL works fine. I'd suggest that you rename your table "Group" as it's a reserved word in SQL and you'll have to back tick it every time as I do in this sql.
select a.AnimalName, g.groupName
from Animal a
JOIN TableGroup_Animal tga ON a.idAnimal = tga.idAnimal
JOIN `Group` g on g.idGroup= tga.idGroup;
Here's the schema I created and data to help anyone trying to prototype this.
CREATE TABLE `Animal` (
`idAnimal` INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
`animalName` varchar(128)
);
CREATE TABLE `Group` (
`idGroup` INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
`groupName` varchar(128)
);
CREATE TABLE `TableGroup_Animal` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
`idAnimal` integer,
`idGroup` integer
);
--Seeding animal
insert into `Animal` (animalName) values ('cat');
insert into `Animal` (animalName) values ('Rat');
insert into `Animal` (animalName) values ('Zebra');
insert into `Animal` (animalName) values ('Platypus');
--seeding group
insert into `Group` (groupName) values ('small');
insert into `Group` (groupName) values ('medium');
insert into `Group` (groupName) values ('large');
---seeding group animal pivot table
insert into TableGroup_Animal (idAnimal, idGroup) values (3,2);
insert into TableGroup_Animal (idAnimal, idGroup) values (3,3);
insert into TableGroup_Animal (idAnimal, idGroup) values (1,2);
insert into TableGroup_Animal (idAnimal, idGroup) values (4,2);
insert into TableGroup_Animal (idAnimal, idGroup) values (2,1);
);
insert into TableGroup_Animal (idAnimal, idGroup) values (2,1);
Do this query:
select * from Animal INNER JOIN tableGrupo_Animal ON Animal.idanimal = tableGrupo_Animal.fkanimal INNER JOIN Grupos ON Grupos.idgrupo = tableGrupo_Animal.fkgrupo where Grupos.nomegrupo='wwrt'

copy a column from one table to another where table1.col = table2.col

Suppose there are two tables which have the data mentioned in the insert query. There is no foreign key references between the two table.
create table uref.slave (
SLAVE_ID SMALLINT NOT NULL PRIMARY KEY,
DESC VARCHAR(20)
);
INSERT INTO uref.SLAVE values (1, null)
INSERT INTO uref.SLAVE values (2, null)
create table uref.master (
MASTER_ID SMALLINT NOT NULL PRIMARY KEY,
SLAVE_ID SMALLINT,
DESC VARCHAR(20)
);
INSERT INTO uref.MASTER values (1,1,'value1')
INSERT INTO uref.MASTER values (2,2,'value2')
Now I need a query which will copy uref.master.DESC into uref.slave.DESC based on uref.master.SLAVE_ID = uref.slave.SLAVE_ID.
The simplest solution may be to use MERGE.
MERGE INTO uref.SLAVE s
USING uref.MASTER m
ON (s.SLAVE_ID = m.SLAVE_ID)
WHEN MATCHED
THEN UPDATE SET Desc = m.Desc
It could be refined to update only when there is a change to be made
MERGE INTO uref.SLAVE s
USING uref.MASTER m
ON (s.SLAVE_ID = m.SLAVE_ID)
WHEN MATCHED
and ( s.Desc <> m.Desc
or (s.Desc is null and m.Desc is not null)
)
THEN UPDATE SET Desc = m.Desc
UPDATE uref.SLAVE t1
SET Desc =
(
SELECT t2.Desc
FROM uref.MASTER t2
WHERE t1.SLAVE_ID = t2.SLAVE_ID
)
WHERE EXISTS
(
SELECT *
FROM uref.MASTER t2
WHERE t1.SLAVE_ID = t2.SLAVE_ID
AND NOT t1.Desc=t2.Desc
)
AND t1.Desc IS NULL
if sql server, Try below sql: (recheck the table name and fields)
declare #urefSlave table (
SLAVE_ID SMALLINT ,
[DESC] VARCHAR(20)
);
INSERT INTO #urefSlave values (1, null)
INSERT INTO #urefSlave values (2, null)
Declare #urefMaster table (
MASTER_ID SMALLINT,
SLAVE_ID SMALLINT,
[DESC] VARCHAR(20)
);
INSERT INTO #urefMaster values (1,1,'value1')
INSERT INTO #urefMaster values (2,2,'value2')
select * from #urefMaster
select * from #urefSlave
update #urefSlave
set [DESC] = b.[DESC]
from #urefSlave a inner join #urefMaster b on a.SLAVE_ID = b.SLAVE_ID
select * from #urefSlave
REsult:
MASTER_ID SLAVE_ID DESC
--------- -------- --------------------
1 1 value1
2 2 value2
SLAVE_ID DESC
-------- --------------------
1 value1
2 value2
Updated
cannot help much in db2, because i don't have the tools to run the syntax
but from this link db2 update help
you can modify an example in there to meet your requirement:
UPDATE EMPLOYEE EU
SET (EU.SALARY, EU.COMM)
=
(SELECT AVG(ES.SALARY), AVG(ES.COMM)
FROM EMPLOYEE ES
WHERE ES.WORKDEPT = EU.WORKDEPT)
WHERE EU.EMPNO = '000120'
Hope this help.

Insert a row if it doesn't exist via query

I am trying to write a query that will insert a group of people into a table if that person does not exist. For example, I have table full of people and I need to add more people into the database and I don't know if they are already there. I do know that the social security number (ssn) will never be the same for two people. Could a query be used to check if the ssn is in the table and if not insert the person into the table? If the ssn is in the table then go to the next person and check?
I was thinking about using a stored procedure, but I do not have any rights to create a store procedure.
You can insert your data into a table variable or temp table and then INSERT INTO table from temp table where it does not exists in your table.
DECLARE #Inserted AS TABLE
(
NAME VARCHAR(50)
,SSN DECIMAL(10, 0)
)
INSERT INTO #Inserted
( NAME, SSN )
VALUES ( 'Bob', 123456789 )
, ( 'John', 123546789 )
, ( 'James', 123456798 )
INSERT INTO MyTable
SELECT *
FROM #Inserted AS i
LEFT OUTER JOIN MyTable AS m
ON i.SSN = m.SSN
WHERE m.SSN IS NULL
Here are a couple ideas to get you started. I use MERGE a lot because it offers so much control. You could also look into the IN clause as part of a WHERE predicate in the INSERT SELECT statement.
MERGE
DECLARE #PERSONTABLE TABLE (ID INT PRIMARY KEY IDENTITY(1,1), FirstName VARCHAR(max))
INSERT INTO #PERSONTABLE (FirstName) VALUES ('Bill'),('Sally'),('Bob')
DECLARE #NEWPEOPLE TABLE (FirstName VARCHAR(max))
INSERT INTO #NEWPEOPLE (FirstName) VALUES ('Jim'), ('Sally')
--MERGE
MERGE INTO #PERSONTABLE AS T
USING #NEWPEOPLE AS S
ON (T.FirstName = S.FirstName)
WHEN NOT MATCHED BY TARGET THEN
INSERT (FirstName) VALUES (S.FirstName);
SELECT * FROM #PERSONTABLE
EXCEPT
DECLARE #PERSONTABLE TABLE (ID INT PRIMARY KEY IDENTITY(1,1), FirstName VARCHAR(max))
INSERT INTO #PERSONTABLE (FirstName) VALUES ('Bill'),('Sally'),('Bob')
DECLARE #NEWPEOPLE TABLE (FirstName VARCHAR(max))
INSERT INTO #NEWPEOPLE (FirstName) VALUES ('Jim'), ('Sally')
--EXCEPT
INSERT INTO #PERSONTABLE (FirstName)
SELECT FirstName FROM #NEWPEOPLE
EXCEPT
SELECT FirstName FROM #PERSONTABLE
SELECT * FROM #PERSONTABLE
You could do it like this if the new people are in another table. If not, then use Vladimir's solution.
INSERT INTO People(ssn, firstname, lastname)
SELECT ssn, firstname, lastname
FROM newpeople
WHERE ssn not in (select ssn from people )
INSERT INTO People(ssn, firstname, lastname)
SELECT np.ssn, np.firstname, np.lastname
FROM newpeople np
LEFT JOIN People p on np.ssn = p.ssn
WHERE p.ssn IS NULL
Here's another option I use a lot. Normally joins are better than sub-selects... if the joined table value is null you know you don't have a hit in the joined table.

Inserting the Identity of another Insert from Select?

Is This Possible?
Here is something I'm looking for, executed together:
First, it would execute the INSERT based on how many rows in the SELECT
INSERT INTO TABLE2 (xID, NAME)
SELECT xID, NAME FROM TABLE
Then getting the ##IDENTITY of each INSERTED ROW, it would create a new Insert including the same data of the first SELECT statement:
INSERT INTO TABLE3 (xID, NAME, ID)
SELECT xID, NAME, ID as Scope_IdentitY()
If not, what the best way without using cursor or while?
You have, at least, two options:
1) The OUTPUT...INTO target_table clause (SQL2005+)
2) Or you could write composable DML(SQL2008+).
Example:
DECLARE #Table2 TABLE(
ID INT IDENTITY PRIMARY KEY, --IDENTITY
xID INT NOT NULL,
NAME VARCHAR(25) NOT NULL
);
DECLARE #Table3 TABLE(
ID INT PRIMARY KEY, --No IDENTITY
xID INT NOT NULL,
NAME VARCHAR(25) NOT NULL
);
--First solution: OUTPUT ... INTO
INSERT INTO #Table2 (xID, NAME)
OUTPUT inserted.xID, inserted.NAME, inserted.ID INTO #Table3(xID, NAME, ID)
SELECT t.Col1, t.Col2
FROM (SELECT 11,'A' UNION ALL SELECT 22,'B' UNION ALL SELECT 33,'C') AS t(Col1,Col2);
--Second solution: composable DML
INSERT INTO #Table3(xID, NAME, ID)
SELECT src.xID, src.NAME, src.ID
FROM
(
INSERT INTO #Table2 (xID, NAME)
OUTPUT inserted.xID, inserted.NAME, inserted.ID
SELECT t.Col1, t.Col2
FROM (VALUES(44,'D'),(55,'E'),(66,'F')) AS t(Col1,Col2)
) src
SELECT * FROM #Table2
SELECT * FROM #Table3
INSERT INTO TABLE2 (xID, NAME)
OUTPUT
INSERTED.xID, INSERTED.NAME, INSERTED.ID
INTO TABLE3 (xID, NAME, ID)
SELECT xID, NAME FROM [TABLE]
You can declare a table variable and store the output of the rows inserted into dbo.Table2 in this variable and use the table variable as the input for table dbo.Table3.
CREATE TABLE dbo.Table1
(
xid int NOT NULL
, name varchar(30) NOT NULL
);
CREATE TABLE dbo.Table2
(
id int NOT NULL IDENTITY
, xid int NOT NULL
, name varchar(30) NOT NULL
);
CREATE TABLE dbo.Table3
(
id int NOT NULL
, xid int NOT NULL
, name varchar(30) NOT NULL
);
INSERT INTO dbo.Table1 (xid, name) VALUES
(195, 'abc'),
(242, 'def'),
(332, 'ghi');
GO
DECLARE #tempTable table
( id int
, xid int
, name varchar(30)
);
INSERT dbo.Table2
OUTPUT INSERTED.id, INSERTED.xid, INSERTED.name
INTO #tempTable
SELECT xid, name FROM dbo.Table1;
INSERT dbo.Table3 (id, xid, name)
SELECT id, xid, name FROM #tempTable;
SELECT id, xid, name FROM dbo.Table2;
SELECT id, xid, name FROM dbo.Table3;
GO
OK, based on your comments below, try this:
INSERT INTO TABLE2 (xID, NAME)
SELECT xID, NAME FROM TABLE;
INSERT INTO TABLE3 (xID, NAME, ID)
SELECT xID, NAME, ##identity
FROM TABLE2;
Assuming these table structures:
TABLE_A
-----------
X_ID
NAME
TABLE_B
----------------
TABLE_B_ID [PK]
X_ID
NAME
TABLE_C
----------------
TABLE_C_ID [PK]
X_ID
NAME
TABLE_B_ID [FK]
Then wouldn't this work (best in a transaction)?:
-- Grab data from TABLE_A and INSERT INTO TABLE_B
INSERT INTO TABLE_B (
X_ID,
NAME
)
SELECT
X_ID,
NAME
FROM
TABLE_A
-- Grab data from TABLE_B that matches the data imported from TABLE_A
-- and INSERT that data into TABLE_C (incl. the PK from TABLE_B)
INSERT INTO TABLE_C (
X_ID,
NAME,
TABLE_B_ID
)
SELECT
b.X_ID,
b.NAME,
b.TABLE_B_ID
FROM
TABLE_B b
INNER JOIN
TABLE_A a ON a.X_ID = b.X_ID