'Smarter SQL UPDATE between two tables (bill and bill rows)
I have these two SQL tables:
Bills (BillId, Folio, Date, ProductId)
BillsRows (BillRowId, BillId, ProductId, Lot, Quantity, Price)
ProductId
is optional inBills
ProductId
is mandatory inBillsRows
- If all the rows of a bill have the same
ProductId
then the bill will have thatProductId
- If there are mixed
ProductId
within a bill, then the bill will haveProductId = NULL
I have created the following SQL UPDATE but I'm not sure it is efficient:
update Bills
set ProductId = (
select top 1 ProductId
from BillsRows
group by ProductId, BillId
having count(*) = (select count(*) from BillsRows where BillId = Bills.BillId)
and BillId = Bills.BillId
)
The fact that I'm counting all the rows is what makes me think it is not quite efficient.
Is there any smarter alternative than this?
Update: added two samples
Sample 1: Bill should be updated to ProductId=1 because all of the rows have ProductId=1
insert into Bills (BillId, Folio, Date, ProductId) values (1, 324, '2022-04-14', null)
insert into BillsRows (BillRowId, BillId, ProductId) values (1, 1, 1111)
insert into BillsRows (BillRowId, BillId, ProductId) values (2, 1, 1111)
insert into BillsRows (BillRowId, BillId, ProductId) values (3, 1, 1111)
Sample 2: Bill should be updated to ProductId=NULL because it has different products
insert into Bills (BillId, Folio, Date, ProductId) values (2, 325, '2022-04-14', null)
insert into BillsRows (BillRowId, BillId, ProductId) values (4, 2, 1111)
insert into BillsRows (BillRowId, BillId, ProductId) values (5, 2, 2222)
insert into BillsRows (BillRowId, BillId, ProductId) values (6, 2, 3333)
Solution 1:[1]
Maybe something like this
update B
set B.ProductId =R.ProductID
from Bills B inner join
BillsRows R on R.BillID=B.BillID
where not exists
(
select 1
from BillsRows BR where BR.BillId = R.BillId
and B.ProductID<> BR.ProductId
)
Solution 2:[2]
Please try below query. It should be faster.
update Bills
set ProductId = (
select max(ProductId)
from BillsRows
group by BillId
having count(distinct ProductId) =1
and BillId = Bills.BillId
)
Solution 3:[3]
I think this update might be more efficient than what I initially posted:
update Bills
set
Bills.ProductId = (
select
top 1 ProductId
from BillsRows
where BillsRows.BillId = Bills.BillId
)
where BillId in (
select
BillsRowsGrouped.BillId
from (
select
BillsRows.BillId,
BillsRows.ProductId
from BillsRows
group by
BillsRows.BillId,
BillsRows.ProductId
) as BillsRowsGrouped
group by BillsRowsGrouped.BillId
having count(*) = 1
)
If we read from inside to outside...
First we have this:
select
BillsRows.BillId,
BillsRows.ProductId
from BillsRows
group by
BillsRows.BillId,
BillsRows.ProductId
(This returns a virtual table with two columns: BillId
and ProductId
)
Then, I group again, by BillId
, and stick with those with count(*) = 1
select
BillsRowsGrouped.BillId
from (...) as BillsRowsGrouped
group by BillsRowsGrouped.BillId
having count(*) = 1
Finally, I update using the top 1 result from BillsRows and making sure BillId is in the previous query:
update Bills
set
Bills.ProductId = (
select
top 1 ProductId
from BillsRows
where BillsRows.BillId = Bills.BillId
)
where BillId in (...)
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 | DhruvJoshi |
Solution 2 | |
Solution 3 | sports |