Update 2 rows from three based on duplicated value - sql

How can I update all duplicated site_id rows except the last one. I.e. if I have 3 duplicated site ids (2 in this case), how can I update the top two leaving the last (third) one untouched?
temp_id site_id amount
1 2 200
2 2 200
3 2 200
4 3 200
5 3 200
6 4 200
CREATE TABLE #site (temp_id NUMERIC IDENTITY,
site_id NUMERIC PRIMARY KEY
)
INSERT INTO #site VALUES(2),(3),(4)
CREATE TABLE #temp (temp_id NUMERIC IDENTITY,
site_id NUMERIC FOREIGN KEY (site_id) REFERENCES #site(site_id),
amount NUMERIC)
INSERT INTO #temp VALUES(2,200),(2,200),(2,200),(3,200),(3,200),(4,200)
update #temp
set amount = 2
where site_id in (
select distinct table1.site_id
from #temp table1
inner join #temp table2 on table1.site_id = table2.site_id
and table1.temp_id <> table2.temp_id
)
and site_id <> (
select max(site_id)
from #temp
);
SELECT t.* FROM #temp t
JOIN #site s ON s.site_id = t.site_id
DROP TABLE #temp
DROP TABLE #site

UPDATE temp_record
SET …
WHERE site_id = 2
AND temp_id <> (SELECT MAX(temp_id)
FROM my_table
WHERE site_id = 2)
If you want to update all such lines and temp_id is a unique key in temp_record:
UPDATE temp_record
SET …
WHERE temp_id NOT IN (
SELECT MAX(temp_id)
FROM temp_record
GROUP BY site_id)

My preferred way of doing this is with row_number():
with toupdate as (
select t.*,
row_number() over (partition by site_id order by temp_id desc) as seqnum
from t
)
update t
set . . .
where seqnum = 1
I'm not filling in the details. Just giving you an alternative approach.

Related

Merge or join two tables SQL Server

I have a table with two columns Item, Qty and another table with Product, Quantity.
Table A
Item
Qty
a
10
a
15
a
5
b
10
Table b
Product
Quantity
a
10
a
20
b
5
b
5
The output that I'm looking for is this:
item
Qty
Product
Quantity
a
10
a
10
a
15
a
20
a
5
NULL
NULL
b
10
b
5
NULL
NULL
b
5
You will need to have some sort of order to guarantee consistent results. To simulate that, I added IDENTITY columns
Match Product to Item in Order Based on ROW_NUMBER()
DROP TABLE IF EXISTS #Table1
DROP TABLE IF EXISTS #Table2
CREATE TABLE #Table1 (ID INT IDENTITY(1,1),Item CHAR(1),Qty INT)
CREATE TABLE #Table2 (ID INT IDENTITY(1,1),Product CHAR(1),Qty INT)
INSERT INTO #Table1
VALUES ('a',10)
,('a',15)
,('a',5)
,('b',10)
INSERT INTO #Table2
VALUES ('a',10)
,('a',20)
,('b',5)
,('b',5)
;WITH cte_Table1 AS (
SELECT *,RankNum = ROW_NUMBER() OVER (PARTITION BY Item ORDER BY ID)
FROM #Table1
),
cte_Table2 AS (
SELECT *,RankNum = ROW_NUMBER() OVER (PARTITION BY Product ORDER BY ID)
FROM #Table2
)
SELECT *
FROM cte_Table1 AS A
FULL JOIN cte_Table2 AS B
ON A.Item = B.Product
AND A.RankNum = B.RankNum

Finding Occurrence of the duplicate values

I have table with 3 columns (id, Name, Occurrence), I want to update the Occurrence column ,based on the id column, attached snap for the reference.
for example if my id column has "606" value 3 times then my occurrent column should have 3 against all the "606" value.
Below is the method which I tried.
I tried to find the duplicate values using group by and Having clause and saved it in a temp table and from there I tried to join the table value from the temp table.
you can use window functions in an updatable CTE for this.
You haven't supplied any actual sample data so this is untested, however the following should work:
with x as (
select Id, Occurence, count(*) over(partition by Id) qty
from Table
)
update x
set Occurence = Qty;
You can go for GROUP BY based approach also.
declare #TABLE TABLE(ID INT, NAME CHAR(3), occurance int null)
insert into #TABLE VALUES
(1,'AAA',NULL),(1,'AAA',NULL),(2,'CCC',NULL),(3,'DDD',NULL), (3,'DDD',NULL),(4,'EEE',NULL),(5,'FFF',NULL);
;WITH CTE_Table as
(
SELECT ID, COUNT(*) AS Occurance
FROM #table
group by id
)
UPDATE t
SET occurance = c.occurance
FROM #table t
INNER JOIN CTE_Table as c
on C.ID = T.ID
SELECT * FROM #TABLE
ID
NAME
occurance
1
AAA
2
1
AAA
2
2
CCC
1
3
DDD
2
3
DDD
2
4
EEE
1
5
FFF
1
You can use a CTE and calculate row number and update your table base on CTE
;WITH q
AS
(
SELECT Id,COUNT(1) 'RowNum'
FROM YourTable
GROUP BY Id
)
UPDATE YourTable
SET Occurrence=q.RowNum
FROM YourTable t
INNER JOIN q
ON t.Id=q.Id

How to Select one Value for each row after Joining of 2 Tables

I have 2 tables, the first one has 10 distinct values:
,
each GlobalPnID has many values on the second table, I want to join 2 tables and select one random value of PortionKey of the second table that match the condition and move to the next GlobalPnID
SELECT TOP 10 gpnp.PortionKey, tt.GlobalPnID
from #TempTable tt
LEFT JOIN [dbo].[GlobalPartNumberPortions] gpnp ON gpnp.GlobalPnId = tt.GlobalPnID
-- tt is the first table
-- gpnp is the second
SELECT TT.GlobalPnID,X.PortionKey
FROM #TempTable AS TT
CROSS APPLY
(
SELECT TOP 1 R.PortionKey
FROM [dbo].[GlobalPartNumberPortions] AS R
WHERE R.GlobalPnId=TT.GlobalPnID
ORDER BY R.PortionID
)X
You could use Row_Number with a CTE and set the criteria you want, for example:
DECLARE #TempTable TABLE
(
globalpnid INT
)
DECLARE #GlobalPartNumberPortions TABLE
(
portionid INT,
portionkey NVARCHAR(10),
globalpnid INT
)
INSERT INTO #TempTable
(globalpnid)
VALUES (1),(2),(3),(4)
INSERT INTO #GlobalPartNumberPortions
(portionid,
portionkey,
globalpnid)
VALUES (1,'ABC',1),
(2,'XYZ',1),
(3,'AZZ',2),
(4,'QWE',3),
(5,'TYU',4);
WITH cteportion
AS (SELECT portionkey,
globalpnid,
rn = Row_number()
OVER (
partition BY globalpnid
ORDER BY RAND(CHECKSUM(NEWID()))))
FROM #GlobalPartNumberPortions)
SELECT gpnp.portionkey,
tt.globalpnid
FROM #TempTable tt
LEFT JOIN cteportion gpnp
ON tt.globalpnid = gpnp.globalpnid
AND gpnp.rn = 1
This will partition the second table by the globalpnid ordering on ORDER BY RAND(CHECKSUM(NEWID()))) and you can then use this in the join gpnp.rn = 1. In the example I've included, you'll see that GlobalPnID = 1 will alternate between ABC and XYZ.
Edit: as suggested by #Thorsten Kettner in the comment, you can order by RAND(CHECKSUM(NEWID())))

Select records with certain value but exclude if it has another one

So I have this table
Product_ID Client_ID
1 2
1 3
2 2
3 2
Basically I need to select the product_ID's that's exclusive to client_id = 2. In my case it should return only the 2 and 3 product_ID as the one with id = 1 is not exclusive and has multiple clients setup.
Here's how to do it.
First, let's create your table.
create table SomeTable
(
Product_ID int,
Client_ID int
)
Go
insert into SomeTable values(1, 2)
insert into SomeTable values(1, 3)
insert into SomeTable values(2, 2)
insert into SomeTable values(3, 2)
The following script will return a list of all Product_ID values which have just one Client_ID value:
SELECT Product_ID
FROM SomeTable
GROUP BY Product_ID
HAVING COUNT(*) = 1
And you make this a sub-clause to get the results you're looking for:
SELECT st.Product_ID
FROM SomeTable st,
(
SELECT Product_ID
FROM SomeTable
GROUP BY Product_ID
HAVING COUNT(*) = 1
) tmp (Product_ID)
WHERE tmp.Product_ID = st.Product_ID
and st.Client_ID = 2
This will give you the row results (2 and 3) that you're looking for.
Try this:
Select product_id from ClientsProducts where client_id in (
Select client_ID from
(select client_ID,count(product_id) from ClientsProducts
group by client_ID
having count(product_id)=1) a )
Use COUNT and HAVING
SELECT Product_ID
FROM ClientsProducts
GROUP BY Product_ID
HAVING COUNT(Product_ID) = 1
OUTPUT
Product_ID
2
3
SQL Fiddle: http://sqlfiddle.com/#!3/841ba7/14/0

Recursive Update Statement

I need to create a recursive update statement that updates from another table so for ex..
Table1
(
IdNumberGeneratedFromAService INT NOT NULL,
CodeName NVARCHAR(MAX)
)
Table2
(
Table2Id Auto_Increment,
Name NVARCHAR(MAX),
IdNumberThatComesFromTabl1,
CodeNameForTable1ToMatch
)
the issue is CodeNameForTable1ToMatch is not unique so if Table1 has 2 idnumber for the same code and there are two rows in Table2 with the same CodeName I want to update the rows in table2 in sequence so first row gets the first idnumber and second row gets the second id number.
Also want to do it without cursor....
SAMPLE DATA
Table1
idNumber Code
C145-6678-90 Code1
C145-6678-91 Code1
C145-6678-92 Code1
C145-6678-93 Code1
C145-6678-94 Code1
Table 2
AutoIncrementIdNumber Code IdNumber
1 Code1 {NULL}
2 Code1 {NULL}
3 Code1 {NULL}
4 Code1 {NULL}
5 Code1 {NULL}
C145-6678-90 needs to got 1
C145-6678-91 needs to got 2
C145-6678-92 needs to got 3
C145-6678-93 needs to got 4
C145-6678-94 needs to got 5
in one update statement
Using the ROW_NUMBER windowing function on each of the tables, partitioned by the code, you can number each of the rows that have a code in common, then combine the results of that on each query to match rows based on the code and the numbered instance of that code. So the first Code A in Table 1 would matched the first Code A in table 2, and etc.
Sample code showing this (SQL 2005 or higher):
-- Sample code prep
CREATE TABLE #Table1
(
IdNumberGeneratedFromAService INT NOT NULL,
CodeName NVARCHAR(MAX)
);
CREATE TABLE #Table2
(
Table2Id INT NOT NULL IDENTITY(1,1),
Name NVARCHAR(MAX),
IdNumberThatComesFromTabl1 INT NULL,
CodeNameForTable1ToMatch NVARCHAR(MAX)
);
INSERT INTO #Table1(IdNumberGeneratedFromAService, CodeName)
VALUES(100,'Code A'),(150,'Code A'),(200,'Code B'),(250,'Code A'),(300,'Code C'),(400,'Nonexistent');
INSERT INTO #Table2(Name, IdNumberThatComesFromTabl1, CodeNameForTable1ToMatch)
VALUES('A1-100',0,'Code A'),('A2-150',0,'Code A'),('A3-250',0,'Code A'),('B1-200',0,'Code B'),('C1-300',0,'Code C'),('No Id For Me',0,'Code No Id :(');
-- Sample select statement that shows the row numbers
--SELECT *
--FROM
-- (SELECT *, ROW_NUMBER() OVER (Partition By IT2.CodeNameForTable1ToMatch Order By IT2.Table2Id) as RowNum
-- FROM #Table2 IT2) T2
-- INNER JOIN
-- (SELECT *, ROW_NUMBER() OVER (Partition By IT1.CodeName Order By IT1.IdNumberGeneratedFromAService) as RowNum
-- FROM #Table1 IT1) T1
-- ON T1.CodeName = T2.CodeNameForTable1ToMatch AND T1.RowNum = T2.RowNum;
-- Table 2 Before
SELECT * FROM #Table2;
-- Actual update statement
UPDATE #Table2
SET IdNumberThatComesFromTabl1 = T1.IdNumberGeneratedFromAService
FROM #Table2 AT2
INNER JOIN
(SELECT *, ROW_NUMBER() OVER (Partition By IT2.CodeNameForTable1ToMatch Order By IT2.IdNumberThatComesFromTabl1) as RowNum
FROM #Table2 IT2) T2
ON T2.Table2Id = AT2.Table2Id
INNER JOIN
(SELECT *, ROW_NUMBER() OVER (Partition By IT1.CodeName Order By IT1.IdNumberGeneratedFromAService) as RowNum
FROM #Table1 IT1) T1
ON T1.CodeName = T2.CodeNameForTable1ToMatch AND T1.RowNum = T2.RowNum;
-- Table 2 after
SELECT * FROM #Table2;
-- Cleanup
DROP TABLE #Table1;
DROP TABLE #Table2;
I turned your two sample tables into temp tables and added 3 records for 'Code A', a record for 'Code B', and a record for 'Code C'. The codes in table1 are numbered based on the order of the table 1 ID, the codes in Table 2 are ordered by the auto-incrementing Table 2 id. I also included a record in each table that wouldn't have a match in the other. I tried to make the code's descriptive so it would be easier to see that a correct match has occurred (they order for table 2 is important since it has an auto incrementing id)
The commented out sample select is there to help understand how the select works before I join it into the UPDATE statement.
So we can see before the update Table 2 is all 0's, then we update the values in table 2 where the unique table 2 id matches the unique table 2 id from our nicely numbered and matched join, then we select from table 2 again to see the results.
A riff on Tarwn's solution:
with cte1 as (
select code, row_number() over (partition by code order by idNumber) as [rn]
from table1
), cte2 as (
select code, row_number() over (partition by code order by AutoIncrementIdNumber) as [rn]
from table2
)
update cte2
set idNumber = cte1.idNumber
from cte2
inner join cte1
on cte2.code = cte1.code
and cte2.rn = cte1.rn
I only present this because people are often amazed that you can update a common table expression.
This isn't possible without a cursor.