Update statement across multiple fields - sql

I have a table structure (particularly not fond of) where I need to update multiple colums in one row.
Source Table
ID TotalIntake TotalOutput Day
1 1000 500 0
1 1500 1000 1
2 100 200 0
Destination Table (should look like this after update)
ID TotalIntake_0 TotalIntake_1 TotalOutput_0 TotalOutput_1
1 1000 1500 500 1000
2 100 NULL 200 NULL
I tried to use Case when statement, but for some reason it only updates one of each columns and not all the columns across
UPDATE e
Set e.TotalIntake_0 = Case WHEN i.ProcedureDay = 0 Then i.TotalIntake End
,e.TotalIntake_1 = Case WHEN i.ProcedureDay = 1 Then i.TotalIntake End
,e.TotalOutput_0 = Case WHEN i.ProcedureDay = 0 Then i.TotalOutput End
,e.TotalOutput_1 = Case WHEN i.ProcedureDay = 1 Then i.TotalOutput End
FROM DestinationTable e LEFT JOIN SourceTable i ON e.id = i.id
Any ideas greatly appreciated!
Thanks!

Updates on a row are not cumulative. So, only one matching row is used for the update, and you don't know which one. You can do what you want but you need to summarize the rows first and then do the update:
UPDATE e
Set TotalIntake_0 = i.TotalIntake_0,
TotalIntake_1 = TotalIntake_1,
TotalOutput_0 = TotalOutput_0,
TotalOutput_1 = TotalOutput_1
FROM DestinationTable e LEFT JOIN
(select i.id,
TotalIntake_0 = max(Case WHEN i.ProcedureDay = 0 Then i.TotalIntake End),
TotalIntake_1 = max(Case WHEN i.ProcedureDay = 1 Then i.TotalIntake End),
TotalOutput_0 = max(Case WHEN i.ProcedureDay = 0 Then i.TotalOutput End),
TotalOutput_1 = max(Case WHEN i.ProcedureDay = 1 Then i.TotalOutput End)
from SourceTable i
group by i.id
) i
ON e.id = i.id ;
The documentation that describes this is a bit hard to parse:
Use caution when specifying the FROM clause to provide the criteria
for the update operation. The results of an UPDATE statement are
undefined if the statement includes a FROM clause that is not
specified in such a way that only one value is available for each
column occurrence that is updated, that is if the UPDATE statement is
not deterministic. For example, in the UPDATE statement in the
following script, both rows in Table1 meet the qualifications of the
FROM clause in the UPDATE statement; but it is undefined which row
from Table1 is used to update the row in Table2.
I've highlighted the relevant part.

Wouldn't it be simpler to do this in multiple updates?
UPDATE e
SET e.TotalIntake_0 = i.TotalIntake
FROM DestinationTable e
LEFT JOIN SourceTable i ON e.id = i.id
WHERE i.Day = 0
UPDATE e
SET e.TotalIntake_1 = i.TotalIntake
FROM DestinationTable e
LEFT JOIN SourceTable i ON e.id = i.id
WHERE i.Day = 1
Use transactions if necessary.

Related

SQL CASE statement only updates one value froom join table

I am trying to do a case statement to update multiple columns, but only the first value from my join table AS 'b' is getting picked up. Below I have EDLCode = 1 and this value gets picked up. If I set the EDLCode = 2, it does not update anything. I can separate the updates into it's own blocks and those update correctly, but I was hoping to combine and make this code a little more condense. Any ideas?
UPDATE mainTable
SET
col_one = CASE WHEN EDLCode = 1 THEN b.Amount END,
col_two = CASE WHEN EDLCode = 2 THEN b.Amount END
FROM #mainDataTable AS a
INNER JOIN #deductLiabData AS b
ON a.Employee = b.Employee
WHERE b.EDLType = 'D'
Result would be:
EDLCode Amount
1 100
2 200
col_one col_two
100 null

Updating two values, with a second value having a where clause

This may be pointless but I want in ONE query to only the second value when Eligible equals 1, but always update the first value. So if the eligible is already 0 (or something else), don't update eligible. Can I do this in one query?
---Looping through this
UPDATE myTable p
SET p.first= 'C', p.eligible = 0
WHERE id = l_modifier_row_a.id
Desired Results
BEFORE
ID First Eligible
1 A 1
2 B 2
AFTER
ID First Eligible
1 C 0
2 C 2
In Oracle, you can use exists:
UPDATE myTable p
SET p.first = 'C',
p.eligible = 0
WHERE EXISTS (SELECT 1
FROM l_modifier_row_a l
WHERE p.id = l.id AND p.person_id = l.person_id
);
You cannot set a multiple column values sometime but not in others, in a single statement the columns are ALWAYS the same. However, you can conditionally set the value of a column to the existing value or change that value.
update mytable p
set first= 'C'
, eligible = case when p.eligible = 1
then 0
else p.eligible
end
where id = l_modifier_row_a.id ;
This might be doable in a single statement without a loop. But you did not post the loop control so I cannot look further.

SQL Update a Column From a Select

I want to update 1 column (loadStatus) in the Loads table based on if another column (IBLoad) from a joined table is NULL. The end result when running my statement has 0 rows affected. I'm not sure what's wrong here but maybe my WHERE clause is incorrect?
This is the first time I've tried to update from a select so trying to figure it out :)
UPDATE Loads SET loadStatus = 'SCHEDULED'
FROM (
Select L.OID as [LoadID], T.IBLoad, L.loadStatus
From [Loads] L left join [Transaction] T on L.OID = T.IBLoad
Where T.IBLoad is null and load_type = 1 ) i
WHERE Loads.loadStatus = null
you do not need subquery, And use is null instead of = null
UPDATE L
SET loadStatus = 'SCHEDULED'
From [Loads] L left join [Transaction] T on L.OID = T.IBLoad
Where T.IBLoad is null and load_type = 1
and L.loadStatus is null
or use Loads.loadStatus = '' for empty string
You don't need to update from a select in this case. Here is another way to write the query:
UPDATE l
SET loadStatus = 'SCHEDULED'
FROM Loads l
WHERE l.loadStatus IS NULL AND
l.load_type = 1 AND
NOT EXISTS (SELECT 1 FROM [Transaction] t WHERE l.OID = t.IBLoad);

SQL MERGE statement with conditional MATCH clause

As you can see in the code below the MERGE statement is exactly the same except based on the IF statement I'm changing the column that will be merged into the target table. Is there a better way of writing this? As the number of #Event's grow I don't want to be copying and pasting more and more of these as its not maintainable.
IF #Event = 1
BEGIN
MERGE INTO SomeTable
USING (
-- Some Query
) AS A ON SomeTable.Id = A.Id
WHEN MATCHED THEN
UPDATE SET SomeTable.Column1 = SomeTable.Column1 + 1;
END
ELSE IF #Event = 2
BEGIN
MERGE INTO SomeTable
USING (
-- Some Query
) AS A ON SomeTable.Id = A.Id
WHEN MATCHED THEN
UPDATE SET SomeTable.Column2 = SomeTable.Column2 + 1;
END
It might be a matter of debate whether one statement is better than two. But, you can combine these:
MERGE INTO SomeTable
USING (
-- Some Query
) AS A ON SomeTable.Id = A.Id
WHEN MATCHED THEN
UPDATE SET SomeTable.Column1 = (CASE WHEN #Event = 1
THEN SomeTable.Column1 + 1
ELSE SomeTable.Column1
END),
SomeTable.Column2 = (CASE WHEN #Event = 2
THEN SomeTable.Column2 + 1
ELSE SomeTable.Column2
END);
You dont really need a Merge statement for this and yes you can write your UPDATE statement a bit more dynamically. something like this.....
UPDATE ST
SET ST.Column1 = CASE WHEN #Event = 1
THEN ST.Column1 + 1
ELSE ST.Column1 END
,ST.Column2 = CASE WHEN #Event = 2
THEN ST.Column2 + 1
ELSE ST.Column2 END
FROM SomeTable ST
INNER JOIN
(
-- Some Query
) AS A
ON ST.Id = A.Id
Also you might want to read Use Caution with SQL Server's MERGE Statement as well though.

T-SQL Query to check if related col is true and update another table col

I have this 2 tables SupplierOrder and SupplierOrderDetails which are linked by SupplierOrder PK. Now I have this col called isComplete in the SupplierOrder table which I want o update to true once all the values in the SupplierORderDetails table's isComplete are all true for that supplierOrder ID. Please see the attachment for the tables. I have tried myself with this query but I think it could be a better way or more efficient.
SELECT 1
FROM supplierOrder so
inner JOIN supplierOrderdetails sod
ON so.id = sod.supplierOrderID
WHERE so.id = 1
AND sod.isComplete= 1
This should work, I maynot have correct table names but this should work if u change it
UPDATE suplierorder
SET iscomplete = 'true'
WHERE id IN (SELECT suplierorderid
FROM (SELECT suplierorderid,
--case statement to set to 0 if complete and 1 if not complete (i.e any other value null or false)
Sum(CASE
WHEN iscomplete = 'true' THEN 0
ELSE 1
END) AS complete
FROM suplierorderdetails
--make sure we only update the new ones and makes sure that your select records are limited to Just not complete records, so if your tables grow this will make your update statement doesn't take a lot of time
WHERE suplierorderid IN (SELECT id
FROM suplierorder
WHERE iscomplete IS NULL)
--I am grouping on suplierorderid so that we can add all the iscomplete status of each suplierorderid column
GROUP BY suplierorderid) A
--now that the inner query outputs suplierorderid and complete status which will be 0 if everything is complete we are writing below condition
WHERE complete = 0)
All we need is to find supplierOrderID where MIN(isComplete)=1. So it means that ALL isComplete=TRUE
UPDATE supplierOrder SET isComplete=1
WHERE id in
(
SELECT supplierOrderID
FROM supplierOrderdetails
GROUP BY supplierOrderID
HAVING MIN(CAST(isComplete as Int))=1
)
AND
(
(isComplete is NULL ) OR (isComplete = 0)
)
SQLFiddle demo
PS: Since isComplete is a BIT type field you can't use MIN(isComplete) but you can use MIN(CAST(isComplete as Int))