SQL - Update column for each duplicate in other column - sql

I'm looking for an SQL query to update a column to the same Id for each duplicate in another column and then delete each overwritten row from another table.
For example
I have:
IndustryId ProductId ExternalId
144 3332 13
147 3423 13
148 3532 13
2637 63199 32
121 2789 32
I want:
IndustryId ProductId ExternalId
144 3332 13
147 3332 13
148 3332 13
2637 63199 32
121 63199 32
I also need to record the overwritten ProductId values so that I can delete those rows in another table (3423, 3532, and 2789 should be deleted in the other table). Could be in more than one query if neccesary, that doesnt matter.
What is the best way to achieve this?

That isn't too tough, especially if you break out the steps.
Check this out:
if object_id('tempdb..#myData') is not null
drop table #myData;
create table #myData ( industryid int, productId int, externalId int);
insert into #myData (industryId, productId, externalId)
values (144,3332,13);
insert into #myData (industryId, productId, externalId)
values (147,3423,13);
insert into #myData (industryId, productId, externalId)
values (148,3532,13);
insert into #myData (industryId, productId, externalId)
values (2637,63199,32);
insert into #myData (industryId, productId, externalId)
values (121,2789,32);
--select * from #myData;
-------------------------------------------------
if object_id('tempdb..#IdsToKeep') is not null
drop table #IdsToKeep;
if object_id('tempdb..#badRows') is not null
drop table #badRows;
create table #IdsToKeep (externalId int, productId int);
create table #badRows ( industryId int, productId int, externalId int);
insert into #IdsToKeep
select
externalId, min(productId)
from
#myData
group by
externalId;
--- Capture rows that will be changed ---
insert into #badRows
select
md.industryId, md.productId, md.externalId
from
#myData md
left join #IdsToKeep itk on
md.externalId = itk.externalId
and
md.productId = itk.productId
where
itk.productId IS NULL
;
--- Make the update to the main table ---
update
#myData
set
productId = itk.productId
from
#myData
inner join #IdsToKeep itk on #myData.externalId = itk.externalId
;
----------
select * from #mydata;
select * from #badRows;

declare #table table (IndustryId int, ProductId int, ExternalId int) insert into #table values (144,3332,13), (147,3423,13), (148,3532,13), (2637,63199,32), (121,2789,32)
select * from #table
;with cte (productid, externalid) as (select max(productid), ExternalId from #table group by ExternalId) select t.IndustryId, c.productid, c.externalid from cte c right outer join #table t on c.externalid = t.ExternalId

Related

Insert into 2 different data to 2 table at the same time using first data's id

I have 2 tables: Order and product_order. Every order has some product in it and that's because I store products another table.
Table Order:
Id name
Table PRODUCT_ORDER:
id product_id order_id
Before I start to insert, I don't know what the Order Id is. I want to insert the data into both tables at once and I need the order id to do that.
Both id's are auto incremented. I'm using SQL Server. I can insert first order and then find the id of the order and than execute the second insert, but I want to do these both to execute at once.
The output clause is your friend here.
DECLARE #Orders TABLE (OrderID INT IDENTITY, OrderDateUTC DATETIME, CustomerID INT)
DECLARE #OrderItems TABLE (OrderItemID INT IDENTITY, OrderID INT, ProductID INT, Quantity INT, Priority TINYINT)
We'll use these table variables as demo tables with IDs to insert into. You're liking going to be passing the set of items for an order in together, but for the purpose of a demo we'll ad hoc them as a VALUES list.
DECLARE #Output TABLE (OrderID INT)
INSERT INTO #Orders (OrderDateUTC, CustomerID)
OUTPUT INSERTED.OrderID INTO #Output
VALUES (GETUTCDATE(), 1)
We inserted the Order into the Orders table, and used the OUTPUT clause to cause the inserted (and generated by the engine) into the table variable #Output. We can now use this table however we'd like:
INSERT INTO #OrderItems (OrderID, ProductID, Quantity, Priority)
SELECT OrderID, ProductID, Quantity, Priority
FROM (VALUES (5,1,1),(2,1,2),(3,1,3)) AS x(ProductID, Quantity, Priority)
CROSS APPLY #Output
We cross applied it to our items list, and inseted it as if it was any other row.
DELETE FROM #Output
INSERT INTO #Orders (OrderDateUTC, CustomerID)
OUTPUT INSERTED.OrderID INTO #Output
VALUES (GETUTCDATE(), 1)
INSERT INTO #OrderItems (OrderID, ProductID, Quantity, Priority)
SELECT OrderID, ProductID, Quantity, Priority
FROM (VALUES (1,1,1)) AS x(ProductID, Quantity, Priority)
CROSS APPLY #Output
Just to demo a little farther here's another insert. (You likely wouldn't need the DELETE normally, but we're still using the same variable here)
Now when we select that data we can see the two separate orders, with their IDs and the products that belong to them:
SELECT *
FROM #Orders o
INNER JOIN #OrderItems oi
ON o.OrderID = oi.OrderID
OrderID OrderDateUTC CustomerID OrderItemID OrderID ProductID Quantity Priority
------------------------------------------------------------------------------------------------
1 2022-12-08 23:23:21.923 1 1 1 5 1 1
1 2022-12-08 23:23:21.923 1 2 1 2 1 2
1 2022-12-08 23:23:21.923 1 3 1 3 1 3
2 2022-12-08 23:23:21.927 1 4 2 1 1 1
Dale is correct. You cannot insert into multiple tables at once, but if you use a stored procedure to handle your inserts, you can capture the ID and use it in the next insert.
-- table definitions
create table [order]([id] int identity, [name] nvarchar(100))
go
create table [product_order]([id] int identity, [product_id] nvarchar(100), [order_id] int)
go
-- stored procedure to handle inserts
create procedure InsertProductWithOrder(
#OrderName nvarchar(100),
#ProductID nvarchar(100))
as
begin
declare #orderID int
insert into [order] ([name]) values(#OrderName)
select #orderID = ##identity
insert into [product_order]([product_id], [order_id]) values(#ProductID, #orderID)
end
go
-- insert records using the stored procedure
exec InsertProductWithOrder 'Order ONE', 'AAAAA'
exec InsertProductWithOrder 'Order TWO', 'BBBBB'
-- verify the results
select * from [order]
select * from [product_order]

How to retrieve SCOPE_IDENTITY of all inserts done in INSERT INTO [table] SELECT [col1, ...] [duplicate]

This question already has answers here:
SQL Server - Return value after INSERT
(14 answers)
Closed 7 months ago.
Suppose I have a temp table with some cols one of which I have dedicated to identity column of the inserted Invoice and the others for inserting Invoice data itself. Like the following table :
CREATE TABLE #InvoiceItems
(
RowNumber INT, -- Used for inserting new invoice
SaleID INT, -- Used for inserting new invoice
BuyerID INT, -- Used for inserting new invoice
InvoiceID INT -- Intended for PK of the invoice added after inserting it
);
I use something like the following for inserting data into Invoice table
INSERT INTO [Invoice]
SELECT [col1, ...]
FROM #InvoiceItems
How can I achieve to fill the InvoiceID column while inserting table data into Invoice table using temp table? I know about SCOPE_IDENTITY() function but it returns the last inserted PK only which does not really suit my need.
I could also use a while to do this one by one but since the number of data I'm planning to insert is immense, I feel like it's not going to be the most optimized option.
Thanks for the answers in advance.
To grab multiple IDENTITY values from INSERT INTO SELECT FROM OUTPUT clause could be used:
-- temp table
CREATE TABLE #temp(col VARCHAR(100));
INSERT INTO #temp(col) VALUES ('A'), ('B'), ('C');
--target table
CREATE TABLE tab(
id INT IDENTITY,
col VARCHAR(100)
);
Main insert:
INSERT INTO tab(col)
OUTPUT inserted.id, inserted.col
SELECT col
FROM #temp;
The output could be also Inserted into another table using OUTPUT INTO:
CREATE TABLE #temp_identity(id INT);
INSERT INTO tab(col)
OUTPUT inserted.id
INTO #temp_identity
SELECT col
FROM #temp;
SELECT * FROM #temp_identity;
db<>fiddle demo
CREATE TABLE #InvoiceItems(
RowNumber INT,
SaleID INT,
BuyerID INT,
InvoiceID INT
);
INSERT INTO #InvoiceItems (RowNumber, SaleID, BuyerID) values (1, 55, 77)
INSERT INTO #InvoiceItems (RowNumber, SaleID, BuyerID) values (1, 56, 78)
INSERT INTO #InvoiceItems (RowNumber, SaleID, BuyerID) values (1, 57, 79)
INSERT INTO #InvoiceItems (RowNumber, SaleID, BuyerID) values (1, 58, 80)
INSERT INTO #InvoiceItems (RowNumber, SaleID, BuyerID) values (1, 59, 81)
DECLARE #Inserted table( RowNumber int,
SaleID INT,
BuyerID INT,
InvoiceID INT);
INSERT INTO dbo.[Invoice] (RowNumber, SaleID, BuyerID)
OUTPUT INSERTED.RowNumber, INSERTED.SaleID, INSERTED.BuyerID, INSERTED.InvoiceID
INTO #Inserted
SELECT RowNumber, SaleID, BuyerID
FROM #InvoiceItems
UPDATE ii
SET InvoiceID = ins.InvoiceID
FROM #InvoiceItems ii
JOIN #Inserted ins on ins.BuyerID = ii.BuyerID and ins.RowNumber = ii.RowNumber and ins.SaleID = ii.SaleID
SELECT * FROM #InvoiceItems

SQL Server query with join from other table

I have two tables:
cicmpy with columns:
ID ItemCode Description SecurityLevel Type debcode
and table AAA2 with column
KLIENCIID
I need select * from cicmpy with data (ID) from KLIID.
I tried this select statement:
SELECT *
FROM dbo.cicmpy
WHERE debcode IN (SELECT KLIENCIID FROM AAA2)
Example:
SELECT *
FROM dbo.AAA2
KLIENCIID
300000
300001
300002
SELECT *
FROM dbo.cicmpy
WHERE dbo.cicmpy.debcode = 300000;
ID
ItemCode
debcode
46
ED8D7F34-88A6-439B-85FC-AC9B1461E547
300000
Schema and insert statements:
CREATE TABLE dbo.AAA2 (KLIENCIID varchar(10));
INSERT INTO dbo.AAA2 VALUES(300000);
INSERT INTO dbo.AAA2 VALUES(300001);
INSERT INTO dbo.AAA2 VALUES(300002);
CREATE TABLE dbo.cicmpy
(
ID int,
ItemCode varchar(200),
debcode varchar(10)
);
INSERT INTO dbo.cicmpy
VALUES (46, 'ED8D7F34-88A6-439B-85FC-AC9B1461E547', 300000);
Select query:
SELECT c.*
FROM dbo.cicmpy c
INNER JOIN AAA2 a ON LTRIM(RTRIM(c.debcode)) = LTRIM(RTRIM(a.KLIENCIID))
Output:
ID
ItemCode
debcode
46
ED8D7F34-88A6-439B-85FC-AC9B1461E547
300000
db<>fiddle here

SQL - INSERT AND UPDATE Table from a Temp Table

I am trying to insert some data into a Temp Table(#temptable) and after inserting I would Like to perform Sum(amount) which matches the same ID and group by the cust name and the bill ID and I want to select the earliest date available in those matching ID. After all these Operations I would like to update the original table(billtable)
Bill ID Amount CUstName Duedate
12 12.2 ABC 12222016
12 22.2 ABC 12112016
13 23.22 ABC 12102016
Bill ID Amount CUstName Duedate
12 34.4 ABC 12112016
13 23.22 ABC 12102016
you will need something like the below
If(OBJECT_ID('tempdb..#t') Is Not Null)
Begin
Drop Table #t
End
create table #t
(
billid varchar (50),
amount decimal,
cust varchar (50),
duedate datetime
)
insert into #t (billid,amount,cust,duedate) values ('12',12.2,'abc','20161222')
insert into #t (billid,amount,cust,duedate) values ('12',22.2,'abc','20161211')
insert into #t (billid,amount,cust,duedate) values ('13',23.22,'abc','20161210')
insert into #t (billid,amount,cust,duedate) values ('12',34.4,'abc','20161211')
insert into #t (billid,amount,cust,duedate) values ('13',23.22,'abc','20161210')
select billid,sum(amount),MIN(duedate)
from #t
group by billid

Select one records from three tables based on latest date

I have a TransactionMaster table in SQL Server 2012 that has unique TransactionID. The same TransactionID wil be availabe in LowTransaction ,MediumTransaction and HighTransaction tables.
For each TransactionID in TransactionMaster, I need to display one StatusMessage. The StatusMessage may come from any of the 3 tables - based on date formulated from CRTDTEC and CRTTIME columns..
What is the best way in SQL Server 2012 to select the StatusMessage corresponding to latest date?
Note: CRTDTEC Format - YYMMDD and CRTTIME Format - HHMMSS
CODE
DECLARE #TransactionMaster TABLE (TransactionID INT)
DECLARE #LowTransaction TABLE (TransactionID INT, StatusMessage VARCHAR(80), CRTDTEC VARCHAR(8), CRTTIME VARCHAR(6))
DECLARE #MediumTransaction TABLE (TransactionID INT, StatusMessage VARCHAR(80), CRTDTEC VARCHAR(8), CRTTIME VARCHAR(6))
DECLARE #HighTransaction TABLE (TransactionID INT, StatusMessage VARCHAR(80), CRTDTEC VARCHAR(8), CRTTIME VARCHAR(6))
INSERT INTO #TransactionMaster VALUES (1)
INSERT INTO #TransactionMaster VALUES (2)
INSERT INTO #TransactionMaster VALUES (3)
INSERT INTO #LowTransaction VALUES (1,'1 Low','20131213','235959')
INSERT INTO #MediumTransaction VALUES (1,'1','20131213','235900')
INSERT INTO #HighTransaction VALUES (1,'1 High','20111213','235959')
INSERT INTO #LowTransaction VALUES (2,'2 Low','20111213','235959')
INSERT INTO #LowTransaction VALUES (3,'3 Low','20111213','235959')
INSERT INTO #MediumTransaction VALUES (3,'3 Medium','20111213','235959')
INSERT INTO #HighTransaction VALUES (3,'3 High','20140101','235959')
Expected Result
(1,'1 Low','20131213','235959')
(2,'2 Low','20111213','235959')
(3,'3 High','20140101','235959')
The simplest way would probably be
WITH TransConsolidated
AS (SELECT *
FROM #LowTransaction
UNION ALL
SELECT *
FROM #MediumTransaction
UNION ALL
SELECT *
FROM #HighTransaction)
SELECT TM.TransactionID,
CA.*
FROM #TransactionMaster TM
CROSS APPLY (SELECT TOP 1 *
FROM TransConsolidated TC
WHERE TC.TransactionID = TM.TransactionID
ORDER BY CRTDTEC DESC,
CRTTIME DESC) CA
Or another possibility (if there is a covering index ordered by TransactionID on all tables) would be to merge join all four tables involved
;WITH CTE
AS (SELECT TM.TransactionID,
MAX(CA.CRTDTEC + CA.CRTTIME + CA.StatusMessage) AS MaxRow
FROM #TransactionMaster TM
LEFT MERGE JOIN #LowTransaction LT
ON LT.TransactionID = TM.TransactionID
LEFT MERGE JOIN #MediumTransaction MT
ON MT.TransactionID = TM.TransactionID
LEFT MERGE JOIN #HighTransaction HT
ON HT.TransactionID = TM.TransactionID
CROSS APPLY (SELECT LT.*
UNION ALL
SELECT MT.*
UNION ALL
SELECT HT.*) CA
GROUP BY TM.TransactionID)
SELECT TransactionID,
SUBSTRING(MaxRow, 1, 8),
SUBSTRING(MaxRow, 9, 6),
SUBSTRING(MaxRow, 16, 80)
FROM CTE
I guess you could do something like this...
SELECT TransactionID, StatusMessage, CRTDTEC, CRTTIME
FROM
(
SELECT *, rn = ROW_NUMBER() OVER (PARTITION BY TransactionID ORDER BY CRTDTEC DESC)
FROM
(
SELECT * FROM #LowTransaction
UNION ALL
SELECT * FROM #MediumTransaction
UNION ALL
SELECT * FROM #HighTransaction
)q
) q2
WHERE rn = 1
Result Set
TransactionID StatusMessage CRTDTEC CRTTIME
1 1 Low 20131213 235959
2 2 Low 20111213 235959
3 3 High 20140101 235959