'What is the quickest way to update each row in one table with a use-once value from another table?
I have a table called dbo.RecycleProductID that has just a primary key ProductID column and a Used column:
ProductID (pk, int) | Used (bit)
23 1
65 1
68 1
90 NULL
104 NULL
...
60983471 NULL
The table above has about 6.5m ProductID values that need to be 'recycled' and assigned to products in a different table. Once a ProductID has been assigned to a product, I must update the Used column value to 1 to indicate it has been used. There are gaps in the ProductID sequence, some in the thousands (.e.g it can jump from 1010 to 8055) and there are way more rows in this table than the receiving table dbo.Product table.
The dbo.Product table (has about 1.5m rows) is just a list of products but with no ProductID values.
ProductID (pk, int) | ProductName (varchar)
23 Toothpaste
65 Speakers
68 Galaxy S8
NULL Plate
NULL Monitor
NULL Carpet
.....
I am currently running a while loop to get the ProductID values from dbo.RecycleProductID into the dbo.Product table:
DECLARE @Max int = (select max(ProductID) from [dbo].[RecycleProductID]);
DECLARE @Min int = (select min(ProductID) from [dbo].[RecycleProductID]);
while @Min <= @Max
begin
UPDATE TOP (1)
[dbo].[Product]
SET ProductID = (SELECT TOP 1 ProductID FROM [dbo].[RecycleProductID] b1 WHERE b1.Used IS NULL ORDER BY ProductID ASC)
OUTPUT INSERTED.ProductID INTO dbo.UsedProductID
WHERE
ProductID is null;
UPDATE
rp1
SET
rp1.Used = 1
FROM
[dbo].[RecycleProductID] rp1
INNER JOIN
dbo.UsedProductID ub1 ON
ub1.ProductID = rp1.ProductID
set @Min = @Min+1
end;
With this basically being a CURSOR, it is taking forever. It has been running for almost two days and only updated about 326515 rows. Is there a quicker way of doing this?
Solution 1:[1]
Try this query:
with t1 as (
select
ProducID, row_number() over (order by ProducID) rn
from
RecycleProductID
where
used is null
)
, t2 as (
select
ProducID, row_number() over (order by ProducID) rn
from
Product
where
ProductID is null
)
update t2
set t2.ProducID = t1.ProducID
from
t2
join t1 on t2.rn = t1.rn
EDIT: This query will update RecycleProductID and can be executed seperately
update RecycleProductID
set used = 1
where ProducID in (select ProductID from Product)
Solution 2:[2]
Because MYSQL don't allow update on WITH, you can use this query to do the job on MYSQL :
with t1 as (
select
ProducID, row_number() over (order by ProducID) rn
from
RecycleProductID
where
used is null
)
, t2 as (
select
ID, ProducID, row_number() over (order by ProducID) rn
from
Product
where
ProductID is null
)
update Product t3
join t2 on t2.ID = t3.ID
join t1 on t1.rn = t2.rn
set t3.ProducID = t1.ProducID;
Solution 3:[3]
Like the accepted solution
For the second update try
update RecycleProductID
set used = 1
from RecycleProductID
join Product
on RecycleProductID.ProductID = Product.ProductID
and used is null
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | NDedob |
| Solution 3 | paparazzo |
