SQL CASE statement only updates one value froom join table - sql

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

Related

Join two tables on multiple conditions Using Oracle SQL

I have a 2 Tables with below structures
Table 1-- Containing Values like this.
OTHER_CODE
CAPACITY_CODE
Result
A
1
A
5
A
9
A
(null)
B
2
B
6
B
2
Table_2- With Values Like
OTHER_CODE
CAPACITY_CODE
Result
A
1
A
A
5
B
A
(null)
C
A
ELSE
D
B
ALL
E
(null)
ALL
F
I need to Join Table_1 with Table_2 on basis of columns OTHERCODE and CAPACITYCODE and update values in Column Result of Table**1 **using a Merge statement.
I need to handle and match Values based on ELSE and ALL values too.
Check for Direct Match
Check if ALL or ELSE condition
The Final TABLE_1 must look like
OTHER_CODE
CAPACITY_CODE
Result
Explanation
A
1
A
Direct Join
A
5
B
Direct Join
A
9
D
Satsifying ELSE condition
A
(null)
C
Direct join with NVL handling
B
2
E
As Value for CapacityCode in TableB is ALL
B
6
E
As Value for CapacityCode in TableB is ALL
B
2
E
As Value for CapacityCode in TableB is ALL
I Tried Joining both the tables but the was unable to satisfy Else and ALL conditions. Hope if someone can help me on this.
There are Several **Result ** Columns like , Result 1 ,2 in both tables which needs to be updated using the same logic.
Thanks in Advance.
here is a fiddle to work on https://dbfiddle.uk/FMKdWzQT
I got the query working. by using a case statement and assigning a number so I could use max then I just remove the number.
SELECT a.other_code,
a.capacity_code,
(
SELECT SUBSTR(max(
CASE WHEN b.other_code = a.other_code AND a.capacity_code = b.capacity_code THEN concat('3',b.myresult)
WHEN b.other_code = a.other_code AND a.capacity_code is null and b.capacity_code is null THEN concat('2',b.myresult)
WHEN b.other_code = a.other_code AND b.capacity_code in ('ELSE', 'ALL') THEN concat('1',b.myresult)
else null end),2)
FROM table2 b ) as myresult
FROM table1 a
however I can not get the update to work. I tried a merge it is give me the unstable row error and I tried an update select but that is giving me single row subquery error so maybe someone else can take a look at the fiddle. here was my attempt at the update.
UPDATE table1
SET myresult = (
SELECT myresult
FROM (
SELECT a.other_code,
a.capacity_code,
(
SELECT SUBSTR(max(
CASE WHEN b.other_code = a.other_code AND a.capacity_code = b.capacity_code THEN concat('3',b.myresult)
WHEN b.other_code = a.other_code AND a.capacity_code is null and b.capacity_code is null THEN concat('2',b.myresult)
WHEN b.other_code = a.other_code AND b.capacity_code in ('ELSE', 'ALL') THEN concat('1',b.myresult)
else null end),2)
FROM table2 b ) as myresult
FROM table1 a
)t2
WHERE table1.other_code = t2.other_code and nvl(table1.capacity_code,'x') = nvl(t2.capacity_code,'x')
);

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.

T-SQL cursor or if or case when

I have this table:
Table_NAME_A:
quotid itration QStatus
--------------------------------
5329 1 Assigned
5329 2 Inreview
5329 3 sold
4329 1 sold
4329 2 sold
3214 1 assigned
3214 2 Inreview
Result output should look like this:
quotid itration QStatus
------------------------------
5329 3 sold
4329 2 sold
3214 2 Inreview
T-SQL query, so basically I want the data within "sold" status if not there then "inreview" if not there then "assigned" and also at the same time if "sold" or "inreview" or "assigned" has multiple iteration then i want the highest "iteration".
Please help me, thanks in advance :)
This is a prioritization query. One way to do this is with successive comparisons in a union all:
select a.*
from table_a a
where quote_status = 'sold'
union all
select a.*
from table_a a
where quote_status = 'Inreview' and
not exists (select 1 from table_a a2 where a2.quoteid = a.quoteid and a2.quotestatus = 'sold')
union all
select a.*
from table_a a
where quote_status = 'assigned' and
not exists (select 1
from table_a a2
where a2.quoteid = a.quoteid and a2.quotestatus in ('sold', 'Inreview')
);
For performance on a larger set of data, you would want an index on table_a(quoteid, quotestatus).
You want neither cursors nor if/then for this. Instead, you'll use a series of self-joins to get these results. I'll also use a CTE to simplify getting the max iteration at each step:
with StatusIterations As
(
SELECT quotID, MAX(itration) Iteration, QStatus
FROM table_NAME_A
GROUP BY quotID, QStats
)
select q.quotID, coalesce(sold.Iteration,rev.Iteration,asngd.Iteration) Iteration,
coalesce(sold.QStatus, rev.QStatus, asngd.QStatus) QStatus
from
--initial pass for list of quotes, to ensure every quote is included in the results
(select distinct quotID from table_NAME_A) q
--one additional pass for each possible status
left join StatusIterations sold on sold.quotID = q.quotID and sold.QStatus = 'sold'
left join StatusIterations rev on rev.quotID = q.quotID and rev.QStatus = 'Inreview'
left join StatusIterations asngd on asngd.quotID = q.quotID and asngd.QStatus = 'assigned'
If you have a table that equates a status with a numeric value, you can further improve on this:
Table: Status
QStatus Sequence
'Sold' 3
'Inreview' 2
'Assigned' 1
And the code becomes:
select t.quotID, MAX(t.itration) itration, t.QStatus
from
(
select t.quotID, MAX(s.Sequence) As Sequence
from table_NAME_A t
inner join Status s on s.QStatus = t.QStatus
group by t.quotID
) seq
inner join Status s on s.Sequence = seq.Sequence
inner join table_NAME_A t on t.quotID = seq.quotID and t.QStatus = s.QStatus
group by t.quoteID, t.QStatus
The above may look like complicated at first, but it can be faster and it will scale easily beyond three statuses without changing the code.

Update statement across multiple fields

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.

Link tables based on column value

Is it possible to pull values from 2 different tables based on the value of a column? For example, I have a table with a boolean column that either returns 0 or 1 depending on what the end user selects in our program. 0 means that I should pull in the default values. 1 means to use the user's data.
If my table Table1 looked like this:
Case ID Boolean
====================
1 0
2 1
3 1
4 0
5 0
Then I would need to pull Case IDs 1,4,and 5's corresponding data from table Default and Case IDs 3 and 4's corresponding data from table UserDef. Then I would have to take these values, combine them, and reorder them by Case ID so I can preserve the order in the resulting table.
I am fairly inexperienced with SQL but I am trying to learn. Any help or suggestions are greatly appreciated. Thank you in advance for your help.
Something like this:
SELECT
t1.CaseID
,CASE WHEN t1.Boolean = 1 THEN dt.Col1 ELSE ut.Col1 END AS Col1
,CASE WHEN t1.Boolean = 1 THEN dt.Col2 ELSE ut.Col2 END AS Col2
FROM Table1 t1
LEFT JOIN DefaultTable dt ON dt.CaseID = t1.CaseID
LEFT JOIN UserDefTable ut ON ut.CaseID = t1.CaseID
ORDER BY t1.CaseID
You join on both tables and then use CASE in SELECT to choose from which one to display data.
Option B:
WITH CTE_Combo AS
(
SELECT 0 as Boolean, * FROM Default --replace * with needed columns
UNION ALL
SELECT 1 AS Boolean, * FROM UserDef --replace * with needed columns
)
SELECT * FROM Table1 t
LEFT JOIN CTE_Combo c ON t.CaseID = c.CaseID AND t.Boolean = c.Boolean
ORDER BY t.CaseID
This might be even simpler - using CTE make a union of both tables adding artificial column, and then join CTE and your Table using both ID and flag column.
SELECT t1.CaseID,
ISNULL(td.data, tu.data) userData -- pick data from table_default
-- if not null else from table_user
FROM table1 t1
LEFT JOIN table_default td ON t1.CaseID = td.CaseID -- left join with table_default
AND t1.Boolean = 0 -- when boolean = 0
LEFT JOIN table_user tu ON t1.CaseID = tu.CaseID -- left join with table_user
AND t1.Boolean = 1 -- when boolean = 1
ORDER BY t1.CaseID