Updating an is_latest column on redshift table - sql

I'm attempting to update an is_latest column on a redshift table grouped by source and source_primary_key with the following update statement, but getting an error that window functions are not allowed in update statements. What is the best way to go about this?
update my_schema.production_log
set is_latest =
case when run_start_time = max(run_start_time) over (partition by
source, source_primary_key)
then ‘t’ else ‘f’
end

Redshift supports a FROM clause in the update statement. Try this:
update my_schema.production_log
set is_latest = (case when run_start_time = max_run_start_time
then 't' else 'f'
end)
from (select source, source_primary_key, max(run_start_time) as max_run_start_time
from my_schema.production_log
group by source, source_primary_key
) pl2
where pl2.source = production_log.source and
pl2.source_primary_key = production_log.source_primary_key;

You need to rewrite the query so it can join to a derived table:
UPDATE u
SET u.is_latest =CASE
WHEN u.run_start_time = j.max_time THEN 't'
ELSE 'f'
END
FROM my_schema.production_log AS u
INNER JOIN (
SELECT
source
, source_primary_key
, MAX( run_start_time ) max_time
FROM my_schema.production_log
GROUP BY
source
, source_primary_key
) AS j
ON u.source = j.source
AND u.source_primary_key = j.source_primary_key

Related

Conditional update either column1 or column2 or column3

I want to write a SQL update statement like
UPDATE p
SET CASE WHEN inv.name='your' THEN p.your_qty=inv.qty
CASE WHEN inv.name='other' THEN p.other_qty=inv.qty
CASE WHEN inv.name='my' THEN p.my_qty=inv.qty
FROM products p
JOIN Qty_products_inv inv
ON p.itemNo= inv.itemNo
You need to update all three columns. SET can not update different columns on different rows.
So, pivot your source before joining, then set each column back to its existing value if there is no new value to pick up...
UPDATE
p
SET
your_qty = COALESCE(inv.your_qty , p.your_qty ),
other_qty = COALESCE(inv.other_qty, p.other_qty),
my_qty = COALESCE(inv.my_qty , p.my_qty )
FROM
products p
JOIN
(
SELECT
itemNo,
MAX(CASE WHEN name='your' THEN qty END) AS your_qty,
MAX(CASE WHEN name='other' THEN qty END) AS other_qty,
MAX(CASE WHEN name='my' THEN qty END) AS my_qty
FROM
qty_products_inv
GROUP BY
itemNo
)
inv
ON p.itemNo = inv.itemNo
Apologies for typos I'm on my phone.
EDIT:
Don't do the following, from my original answer, as #JonArmstrong's comment shows it does not work (unless each row is only ever picking up one single change).
UPDATE
p
SET
your_qty = CASE WHEN inv.name='your' THEN inv.qty ELSE p.your_qty END,
other_qty = CASE WHEN inv.name='other' THEN inv.qty ELSE p.other_qty END,
my_qty = CASE WHEN inv.name='my' THEN inv.qty ELSE p.my_qty END
FROM
products p
JOIN
qty_products_inv inv
ON p.itemNo = inv.itemNo

where condition to the on clause

I need to modify this sql using a case condition, I need qty to be populated as '1' if serial_number table have the inventory tag available (serial_number.tag_id = inventory.tag_id) else the qty needs to populate from the query results
What would be the best way to do this?
SELECT
* from ( SELECT
inventory.tag_id PalletNumber,
inventory.sku_id sku,
inventory.batch_id batch,
**inventory.qty_on_hand qty,**
inventory.condition_id status,
inventory.user_def_type_1 reasoncode,
serial_number.serial_number serialnumber,
TO_CHAR(inventory.expiry_dstamp, 'YYYY-MM-DD') Expiry_Date,
pre_advice_header.pre_advice_id asn,
pre_advice_header.status asnstatus,
inventory.supplier_id vendor,
TO_CHAR(inventory.receipt_dstamp, 'YYYY-MM-DD') ArrivalDate,
pre_advice_line.host_pre_advice_id PONumber
FROM
inventory
JOIN pre_advice_header ON pre_advice_header.pre_advice_id = inventory.receipt_id
AND pre_advice_header.site_id = inventory.site_id
AND pre_advice_header.client_id = inventory.client_id
AND pre_advice_header.status in ('Complete')
AND pre_advice_header.status is not NULL
LEFT OUTER JOIN pre_advice_line ON pre_advice_line.pre_advice_id = inventory.receipt_id
AND pre_advice_line.sku_id = inventory.sku_id
LEFT JOIN serial_number ON **serial_number.tag_id = inventory.tag_id**
AND serial_number.site_id = inventory.site_id
AND serial_number.client_id = inventory.client_id
AND serial_number.receipt_id = inventory.receipt_id
AND serial_number.sku_id = inventory.sku_id
WHERE
inventory.site_id = 'UK-CBY-04'AND inventory.client_id = 'MLC796'
AND (inventory.condition_id != 'SC1' or inventory.condition_id is null)
AND (inventory.zone_1 <> '80SHP01' or inventory.zone_1 is null)
GROUP BY
inventory.tag_id,
inventory.sku_id,
inventory.batch_id,
inventory.qty_on_hand,
inventory.condition_id,
inventory.user_def_type_1,
serial_number.serial_number,
inventory.expiry_dstamp,
pre_advice_header.pre_advice_id,
pre_advice_header.status,
inventory.supplier_id,
inventory.receipt_dstamp,
pre_advice_line.host_pre_advice_id
ORDER BY
inventory.sku_id DESC,
inventory.tag_id ASC
)
The solution will be as follows using CASE:
CASE WHEN serial_number.serial_number IS NOT NULL THEN 1 ELSE inventory.qty_on_hand END qty

Using a CASE WHEN statement and an IN (SELECT...FROM) subquery

I'm trying to create a temp table and build out different CASE WHEN logic for two different medications. In short I have two columns of interest for these CASE WHEN statements; procedure_code and ndc_code. There are only 3 procedure codes that I need, but there are about 20 different ndc codes. I created a temp.ndcdrug1 temp table with these ndc codes for medication1 and temp.ndcdrug2 for the ndc codes for medication2 instead of listing out each ndc code individually. My query looks like this:
CREATE TABLE temp.flags AS
SELECT DISTINCT a.userid,
CASE WHEN (procedure_code = 'J7170' OR ndc_code in (select ndc_code from temp.ndcdrug1)) THEN 'Y' ELSE 'N' END AS Drug1,
CASE WHEN (procedure_code = 'J7205' OR procedure_code = 'C9136' OR ndc_code in (select ndc_code from temp.ndcdrug2)) THEN 'Y' ELSE 'N' END AS Drug2,
CASE WHEN (procedure_code = 'J7170' AND procedure_code = 'J7205') THEN 'Y' ELSE 'N' END AS Both
FROM table1 a
LEFT JOIN table2 b
ON a.userid = b.userid
WHERE...
AND...
When I run this, it returns: org.apache.spark.sql.AnalysisException: IN/EXISTS predicate sub-queries can only be used in a Filter.
I could list these ndc_code values out individually, but there are a lot of them so wanted a more efficient way of going about this. Is there a way to use a sub select query like this when writing out CASE WHEN's?
Query.
CREATE TABLE temp.flags AS
SELECT DISTINCT a.userid,
CASE WHEN (
procedure_code = 'J7170' OR
(select min('1') from temp.ndcdrug1 m where m.ndc_code = a.ndc_code) = '1'
) THEN 'Y' ELSE 'N' END AS Drug1,
CASE WHEN (
procedure_code = 'J7205' OR
procedure_code = 'C9136' OR
(select min('1') from temp.ndcdrug2 m where m.ndc_code = a.ndc_code) = '1'
) THEN 'Y' ELSE 'N' END AS Drug2,
CASE WHEN (procedure_code = 'J7170' AND procedure_code = 'J7205')
THEN 'Y' ELSE 'N' END AS Both
FROM table1 a
LEFT JOIN table2 b
ON a.userid = b.userid
WHERE...
AND...

How to use a non-existing column in sql query

I am working in SQL server 2012. I have to write a sql statement where I first assign a value to [Pay_Type], which is a non-existing column (not sure whether it can be called as variable or not) and based upon its value I want to use it in another case statement as shown below
SELECT sp.First_Name, [Pay_Type] = CASE WHEN NOT EXISTS(SELECT '1' FROM
PERSON_SALARY ps WHERE ps.PARTY_ID = sp.PARTY_ID and ps.END_DATE IS NULL)
THEN 'Hourly' ELSE 'Salary' END,
HOURLY_RATE = CASE WHEN [Pay_Type] = 'Hourly' THEN pj.HOURLY_RATE ELSE
'0.00' END
FROM SEC_PERSON sp
LEFT OUTER JOIN PERSON_JOB pj ON sp.PERSON_ID = pj.PERSON_ID
WHERE sp.END_DATE IS NOT NULL
But I am getting "Invalid column name 'Pay_Type' " error.
Column aliases cannot be re-used in the same SELECT where they are define. The typical answer is to use a subquery or CTE. I also like using a lateral join:
SELECT sp.First_Name, s.Pay_Type,
HOURLY_RATE = (CASE WHEN s.Pay_Type = 'Hourly' THEN pj.HOURLY_RATE ELSE
'0.00' END)
FROM SEC_PERSON sp LEFT OUTER JOIN
PERSON_JOB pj
ON sp.PERSON_ID = pj.PERSON_ID OUTER APPLY
(SELECT (CASE WHEN NOT EXISTS (SELECT 1
FROM PERSON_SALARY ps
WHERE ps.PARTY_ID = sp.PARTY_ID and ps.END_DATE IS NULL
)
THEN 'Hourly' ELSE 'Salary'
END) as PayType
) s
WHERE sp.END_DATE IS NOT NULL

How to do inner join in Vertica Update?

I was trying to do a inner join with 3 tables in a update query. I tried to find the solution in multiple sites but didn't get the solution.
Following a sample query I am trying:
UPDATE TGT
SET C1 = CASE WHEN TGT.c2 = SRC.c2 AND SRC.C3 = 'P' THEN SRC.C1 ELSE NULL END,
C2 = CASE WHEN TGT.c2 = SRC.c2 AND SRC.C3 = 'D' THEN SRC.C1 ELSE NULL END
FROM SRC
INNER JOIN SRC1
ON SRC.C9 = SRC1.C9
AND SRC.C9 = TGT.C9;
Thanks in Advance!!
I would expect your syntax to work. (I don't have Vertica handy but its query parser is based on Postgres.)
Perhaps -- unlike Postgres -- JOIN is not allowed in the FROM. Then you can put the join conditions in the WHERE clause:
UPDATE TGT
SET C1 = (CASE WHEN TGT.c2 = SRC.c2 AND SRC.C3 = 'P' THEN SRC.C1 END)
C2 = (CASE WHEN TGT.c2 = SRC.c2 AND SRC.C3 = 'D' THEN SRC.C1 END)
FROM SRC, SRC1
WHERE SRC.C9 = SRC1.C9 AND SRC.C9 = TGT.C9;