SQL Bulk insert/update into a table with data from different tables - sql

I have a requirement to insert/update bulk records as follows.
Source Table 1 :
User ID | Rights |
-------------------
A | Y |
B | N |
-------------------
Source Table 2:
Report ID |
-----------
111 |
222 |
----------
Now I have to insert(Or, update if record exists) Cartesian product of above 'User ID' column and 'Report ID' column into another table as follows:
Target Table:
User ID | Report ID| Rights |
------------------------------
A | 111 | Y |
A | 222 | Y |
B | 111 | N |
B | 222 | N |
------------------------------
I am hitting a performance problem as the source table can have thousands of records.
Suggest me the best way to bulk insert/update.

The simplest way to create the table is:
select UserId, ReportId, Rights
into table3
from table1 cross join table2;
If the table already exists, I would suggest truncating it and inserting everything into it:
truncate table table3;
insert into table3(UserId, ReportId, Rights)
select UserId, ReportId, Rights
into table3
from table1 cross join table2;
Trying to selectively add new rows seems inefficient.

INSERT INTO <Target_Table>
(UserID, ReportID, Rights)
(SELECT UserID, ReportID, Rights
FROM Table1
CROSS JOIN Table2)

declare #t table (ID varchar(10),Name varchar(10))
insert into #t (ID,Name)values ('A','Y')
insert into #t (ID,Name)values ('B','N')
declare #tt table (RepID varchar(10))
insert into #tt (RepID)values (11)
insert into #tt (RepID)values (22)
declare #target table (ID varchar(10),Name varchar(10),Repid INT )
INSERT INTO #target (ID,Name,Repid)
select t.ID,t.Name,tt.RepID from #t t,#tt tt
select * from #target

Related

Nested Insert query

I'm trying to write a nested insert into query and I want to insert the values, which are inserted in "Table1", in a new table "Table3".
"Table3" has exactly the same columns as "Table1", but without the second insert into value into "Table2".
"Table1" already contains old data, but only the new data inserted in "Table1" should be inserted in "Table3".
-- insert new rows in History
INSERT INTO "table1"
([icao24], [callsign])
SELECT
CurInserts.icao24
,CurInserts.[callsign]
FROM
(
-- INSERT new rows FROM temptable IN currenttable
INSERT INTO "table2"
([icao24], [callsign])
OUTPUT
inserted.[icao24]
,inserted.[callsign]
SELECT
T.[icao24]
,T.[callsign]
FROM #TempTable T
LEFT JOIN "table2" Cur
ON T.[icao24] = Cur.[icao24]
WHERE Cur.[icao24] IS NULL
) CurInserts;
You could first insert the inserted into another table variable or a temporary table.
Then insert into the 2 other tables from the table variable.
Demonstration
declare #tmp table (icao24 int, callsign int);
declare #ins table (icao24 int, callsign int);
insert into #tmp (icao24, callsign) values (1,10),(2,20),(3,30);
insert into #ins (icao24, callsign)
select icao24, callsign
from
(
insert into table1 (icao24, callsign)
output inserted.icao24, inserted.callsign
select tmp.icao24, tmp.callsign
from #tmp tmp
left join table1 t on t.icao24 = tmp.icao24
where t.icao24 is null
) q;
insert into table2 (icao24, callsign)
select icao24, callsign
from #ins;
insert into table3 (icao24, callsign)
select icao24, callsign
from #ins;
select * from table1;
select * from table2;
select * from table3;
icao24 | callsign
-----: | -------:
1 | 10
2 | 20
3 | 30
icao24 | callsign
-----: | -------:
1 | 10
2 | 20
3 | 30
icao24 | callsign
-----: | -------:
2 | 20
3 | 30
Demo on db<>fiddle here

Insert value of one column from one table to another table based on where condition

I have one question . Suppose there is one table rules in which column department, action ,left_source and right_source,left_source_id,right_source_id is there .Another table is source table where column is name,I'd .
Now i have to insert rules to rule table but in left_source_id and right_source_id i have to insert value from source table based on I'd column . I need some immediate help .
(Source table column I'd contains all the name of left_source and right_source )
Insert Select...union all..select for example
drop table if exists t,t1;
create table t(id int,leftsource varchar(1),rightsource varchar(1));
create table t1(id int,val varchar(1));
insert into t1 values
(1,'l'),(2,'r');
insert into t
select id,val,null from t1 where id = 1
union all
select id,null,val from t1 where id = 2
select * from t;
+------+------------+-------------+
| id | leftsource | rightsource |
+------+------------+-------------+
| 1 | l | NULL |
| 2 | NULL | r |
+------+------------+-------------+
2 rows in set (0.001 sec)

How to add items from another table based on a string aggregated column

I have 2 tables like this
[Table 1]:
|cust_id| tran |item |
| ------| -----|-------
| id1 | 123 |a,b,c |
| id2 | 234 |b,b |
| id3 | 345 |c,d,a,b|
[Table 2]:
| item. | value |
| ----- | ----- |
| a | 1 |
| b | 2 |
| c | 3 |
| d | 4 |
I want to create a target value by doing a lookup from table 2 in table 1 using big query.
|cust_id| tran.|item |target|
| ------| -----|------|------|
| id1 | 123 |a,b,c | 6
| id2 | 234 |b,b | 4
| id3 | 345 |c,d,a,b| 10
What can I try next?
Consider below simple approach
select *,
( select sum(value)
from unnest(split(item)) item
join table2
using (item)
) target
from table1
if applied to sample data in your question - output is
Try the following:
select t1.cust_id
, t1.tran
, t1.item
, sum(t2.value) as target
from table_1 t1
, UNNEST(split(t1.item ,',')) as item_unnested
LEFT JOIN table_2 t2
on item_unnested=t2.item
group by t1.cust_id
, t1.tran
, t1.item
With your data it gives the following:
Create a center table that splits the item column values on rows and join that table with table2.
Try following
--Cursor is used to split the item data row by row
--#temp is a temporary table
create table #temp (id varchar(10), trans varchar(10), item varchar(10), item1 varchar(10));
DECLARE #item varchar(10);
DECLARE #id varchar(10);
DECLARE #trans varchar(10);
DECLARE item_cusor CURSOR FOR
SELECT *
FROM table1;
OPEN item_cusor
FETCH NEXT FROM item_cusor
INTO #id,#trans,#item
WHILE ##FETCH_STATUS = 0
BEGIN
insert into #temp
SELECT #id,#trans,#item,*
FROM STRING_SPLIT (#item, ',')
FETCH NEXT FROM item_cusor
INTO #id,#trans,#item
END
CLOSE item_cusor;
DEALLOCATE item_cusor;
--select * from temp
select t.id as cust_id, t.trans,t.item , sum(cast(t2.value as int)) as target
from #temp t
JOIN table2 t2
on t.item1=t2.item
group by t.id, t.trans,t.item;
Cursors: https://www.c-sharpcorner.com/article/cursors-in-sql-server/
Temporary tables: https://www.sqlservertutorial.net/sql-server-basics/sql-server-temporary-tables/
String split function: https://learn.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql

TSQL Merge 2 Ids into Temp Table

I'm working on a stored procedure in TSQL on SQL Server 2012. When I call the stored procedure. My problem: I'm inserting the values into a table Projects and want to store the inserted.ProjectId together with oID from the importing table into a temporary Table; I don't store the oID from the importing table into the Projects table.
I'm referring myself to this answer:
Insert Into... Merge... Select (SQL Server)
1) Importing Table: I'm sending a table from C# to SQL with the following values:
oID | Title |
----+----------+
0 | ProjectX |
1 | ProjectY |
2 | ProjectZ |
It looks like this in the stored procedure:
CREATE TYPE [MySchema].[Project] AS TABLE
(
oID INT,
Title VARCHAR(100)
);
#ImportProjects MySchema.Project READONLY
2) Projects Table: I'm inserting the values into the Table Projects, and want to store the inserted.ProjectId as well as the oID from the importing Table into a temporary table:
ProjectId | Title |
----------+----------+
33 | ProjectX |
34 | ProjectY |
35 | ProjectZ |
3) Desired Output, Temporary Table: In my temporary table I want to store the ProjectId as well as the oID from the importing table:
RowID | oID | ProjectId |
--------+-----+--------------+
1 | 0 | 33 |
2 | 1 | 34 |
3 | 2 | 35 |
My Merge query looks like this:
create table Temp (ProjectId INT, oID INT)
MERGE INTO Temp USING
(
SELECT
a.oID as oID,
b.ProjectId as ProjectId
FROM #ImportProjects a
CROSS JOIN Projects b
) AS s ON 1 = 0
WHEN NOT MATCHED THEN
INSERT (oID, ProjectId)
VALUES (s.oID, s.ProjectId)
OUTPUT Inserted.ProjectId, s.oID
INTO Temp(oID, ProjectId);
This doesn't really work... One of my problems is of course the cross join, but i dont have a link or foreign key inbetween importing table and projects table...
Do you know how to achieve this?
Thank you !! :)
Your merge attempt is a little confusing, but I think this is what you want instead:
create table tvp (oid int, Title varchar(100));
insert into tvp values (0,'ProjectX'),(1,'ProjectY'),(2,'ProjectZ');
create table #tmp (
Id int not null identity(1,1)
, oid int
, ProjectId int
, Title varchar(100)
);
create table Project (
ProjectId int not null identity(33,1)
, Title varchar(100)
);
merge into Project as Target
using tvp as Source
on 1 = 0
when not matched then
insert (Title)
values (source.Title)
output source.oid, Inserted.ProjectId, Inserted.Title
into #tmp;
select * from #tmp;
rextester demo: http://rextester.com/PIRFA34601
returns:
+-----+-----+-----------+----------+
| Id | oid | ProjectId | Title |
+-----+-----+-----------+----------+
| 1 | 0 | 33 | ProjectX |
| 2 | 1 | 34 | ProjectY |
| 3 | 2 | 35 | ProjectZ |
+-----+-----+-----------+----------+
Rextester does not support table types (because they can not be declared and used in the same transaction), so I used the table tvp instead.
replace CROSS JOIN with INNER JOIN. Foreign key is not requered for inner join
create table Temp (ProjectId INT, oID INT)
MERGE INTO Temp USING
(
SELECT
a.oID as oID,
b.ProjectId as ProjectId
FROM #ImportProjects a
INNER JOIN JOIN Projects b ON a.Title = b.Title
) AS s ON 1 = 0
WHEN NOT MATCHED THEN
INSERT (oID, ProjectId)
VALUES (s.oID, s.ProjectId)
OUTPUT Inserted.ProjectId, s.oID
INTO Temp(oID, ProjectId);

Getting the Next Available Row

How can I get a List all the JobPositionNames having the lowest jobPositionId when ContactId = 1
Tablel :
| JobPositionId | JobPositionName | JobDescriptionId | JobCategoryId | ContactId
---------------------------------------------------------------------------------
1 | Audio Cables | 1 | 1 | 1
2 |Audio Connections| 2 | 1 | 1
3 |Audio Connections| 2 | 1 | 0
4 |Audio Connections| 2 | 1 | 0
5 | Sound Board | 3 | 1 | 0
6 | Tent Pen | 4 | 3 | 0
eg the result of this table should be lines 1,3,5,6
I can't figure out the solution.
Only lack of something, but I can give some code for you view.
Maybe it can help you.
--create table
create table t
(
JobPositionId int identity(1,1) primary key,
JobPositionName nvarchar(100) not null,
JobDescriptionId int,
JobCategoryId int,
ContactId int
)
go
--insert values
BEGIN TRAN
INSERT INTO t VALUES ('AudioCables', 1,1,1)
INSERT INTO t VALUES ('AudioConnections',2,1,1)
INSERT INTO t VALUES ('AudioConnections',2,1,0)
INSERT INTO t VALUES ('AudioConnections',2,1,0)
INSERT INTO t VALUES ('SoundBoard',3,1,0)
INSERT INTO t VALUES ('TentPen',4,3,0)
COMMIT TRAN
GO
SELECT
Min(JobPositionId) AS JobPositionId, JobPositionName, ContactId
INTO
#tempTable
FROM
t
GROUP BY JobPositionName, ContactId
SELECT * FROM #tempTable
WHERE JobPositionId IN (
SELECT JobPositionId
FROM #tempTable
GROUP BY JobPositionName
--... lack of sth, I can't figure out ,sorry.
)
drop table t
GO
For per-group maximum/minimum queries you can use a null-self-join as well as strategies like subselects. This is generally faster in MySQL.
SELECT j0.JobPositionId, j0.JobPositionName, j0.ContactId
FROM Jobs AS j0
LEFT JOIN Jobs AS j1 ON j1.JobPositionName=j0.JobPositionName
AND (
(j1.ContactId<>0)<(j0.ContactId<>0)
OR ((j1.ContactId<>0)=(j0.ContactId<>0) AND j1.JobPositionId<j0.JobPositionId))
)
WHERE j1.JobPositionName IS NULL
This says, for each JobPositionName, find a row for which there exists no other row with a lower ordering value. The ordering value here is a composite [ContactId-non-zeroness, JobPositionId].
(Aside: shouldn't JobPositionName and JobCategoryId be normalised out into a table keyed on JobDescriptionId? And shouldn't unassigned ContactIds be NULL?)
SELECT jp.*
FROM (
SELECT JobPositionName, JobPositionId, COUNT(*) AS cnt
FROM JobPosisions
) jpd
JOIN JobPosisions jp
ON jp.JobPositionId =
IF(
cnt = 1,
jpd.JobPositionId,
(
SELECT MIN(JobPositionId)
FROM JobPositions jpi
WHERE jpi.JobPositionName = jpd.JobPositionName
AND jpi.ContactID = 0
)
)
Create an index on (JobPositionName, ContactId, JobPositionId) for this to work fast.
Note that if will not return the jobs having more than one position, neither of which has ContactID = 0