问题
A bit new to SQL - the db is Snowflake, which I believe is ANSI
Main table shown below. Combinations of same Issue/UPC/Warehouse/Date can be possible, since a new record is added whenever a new issue is reported. Other columns exist, but should not affect this question
The exclude column is what I'm trying to figure out - it should be 'Y' if the desired combination of Issue/UPC/Warehouse and Date is in the Exclusion table, shown below.
The tricky part is the LEVEL column, defining if a UPC/Issue/Warehouse combination must match, or just UPC/Issue, or just UPC. Also, the records in the main table must fall within the Date range to be excluded.
Visually, expected result is this
This solution works for just one level (Issue/UPC/Warehouse), but I can't figure out how to do the other two without overlap and the possibility of excluding records on accident.
update t
set exclude = 'Y'
where exists (select 1
from exclusions e
where e.issue_code = t.issue_code and
e.upc = t.upc and
e.warehouse = t.warehouse and
t.date between e.date_from and e.date_to);
回答1:
David's answer has covered the right approach to take, using the CASE conditional expression, but ensure that your query also incorporates the level check into each condition explicitly. Here's a verbose example:
update t
set exclude = case
when exists(
select 1
from exclusions e
where
e.warehouse = t.warehouse
and e.upc = t.upc
and e.issue_code = t.issue_code
and t.date between e.date_from and e.date_to
and e.level = 'UPC/ISSUE/WAREHOUSE'
) then 'Y'
when exists(
select 1
from exclusions e
where
e.issue_code = t.issue_code
and e.upc = t.upc
and t.date between e.date_from and e.date_to
and e.level = 'UPC/ISSUE'
) then 'Y'
when exists(
select 1
from exclusions e
where
e.upc = t.upc
and t.date between e.date_from and e.date_to
and e.level = 'UPC'
) then 'Y'
else ''
end;
回答2:
I'm not following what your solution is missing, but You can handle multiple different situations/outputs for the column with a case statement. Only the first one that matches will apply so it can prevent overlap.
Something like this:
update t
set exclude = CASE
WHEN EXISTS
(select 1
from exclusions e
where e.issue_code = t.issue_code and
e.upc = t.upc and
e.warehouse = t.warehouse and
t.date between e.date_from and e.date_to
) THEN 'Y'
WHEN --Other situation where it meets your criteria
THEN 'Y'
ELSE 'N'
END
;
You could also use this to invert your logic to specify 'N' situations and default to 'Y' if that makes more sense.
回答3:
If I ignore the level
column, then I can just use null
to see if there is a match. If that suffices, then:
update t
set exclude = 'Y'
where exists (select 1
from exclusions e
where (e.issue_code = t.issue_code or e.issue_code is null) and
(e.upc = t.upc or e.upc is null) and
(e.warehouse = t.warehouse or e.warehouse is null) and
t.date between e.date_from and e.date_to
);
You can use the level
column as well (I think the above is clearer). Something like this:
update t
set exclude = 'Y'
where exists (select 1
from exclusions e
where (e.issue_code = t.issue_code or e.level not like '%ISSUE%') and
(e.upc = t.upc or e.level not like '%UPC%') and
(e.warehouse = t.warehouse or e.level like '%WAREHOUSE%') and
t.date between e.date_from and e.date_to
);
回答4:
I agree with what David said, what you need is an update with case statement. Be bit careful with case statement - only the first criteria that is met will be executed. so code for the most common case first, then next most common .. to finally the least common criteria.
来源:https://stackoverflow.com/questions/62442059/sql-set-conditional-value-based-on-varying-criteria-in-another-table