SQL Case Update to two different column based on select - sql

I'm trying to perform what I believe a very simple case-update SQL to two different column based on a select:
PROD_TB:
Product_Code Reg_Price Sale_Price
A 1000 2000
PRICE_TB:
Product_Code Type Price
A REG 3000
A SALE 4000
Desired update result:
PROD_TB:
Product_Code Reg_Price Sale_Price
A 3000 4000
What I attempted:
UPDATE PROD_TB
SET Reg_Price = CASE
WHEN PRICE_TB.Type = 'REG'
THEN PRICE_TB.Price
ELSE Reg_Price
END,
Sale_Price = CASE
WHEN PRICE_TB.Type = 'SALE'
THEN PRICE_TB.Price
ELSE Sale_Price
END
FROM
PROD_TB
JOIN
PRICE_TB ON PROD_TB.PRODUCT_CODE = PRICE_TB.PRODUCT_CODE
Running the above SQL only updates regular price, not the sale price. Does SQL not support these types of update query? Or did I make an elementary mistake?

Something like this? Basically, just join the set from the PRICE_TB on the condition of which column you want to get from it.
But this is assuming you will only ever have one PRICE_TB.TYPE per updated PROD_TB column name, and that each PROD_TB column always contains a value in PRICE_TB, otherwise it'll be NULL and that row won't be returned. So make sure you know the variations of data that can exist here.
UPDATE PROD
SET Reg_Price = REG.Price, Sale_Price = SALE.Price
FROM PROD_TB PROD
JOIN PRICE_TB REG ON REG.Product_Code = PROD.Product_Code AND REG.Type = 'REG'
JOIN PRICE_TB SALE ON SALE.Product_Code = PROD.Product_Code AND SALE.Type = 'SALE'

You need to get the data into one row first, here's example that fetches always the biggest price, in case there's more than one in PRICE_TB, otherwise it should work the same way as #Kahn's sql.
UPDATE
PROD
SET
PROD.Reg_Price = PRICE.Reg_Price,
PROD.Sales_Price = PRICE.Sales_Price
FROM PROD_TB PROD, cross apply (
select
max(CASE WHEN Type = 'REG' THEN Price ELSE 0 end) as Reg_Price,
max(CASE WHEN Type = 'SALE' THEN Price ELSE 0 end) as Sale_Price
from
PRICE_TB PRICE
where
PRICE.Product_Code = PROD.Product_Code
) PRICE

If your table PRICE_TB doesn't always contain both values, you could use this to make sure the table is updated anyway:
UPDATE t1
SET
Reg_Price = coalesce(t2.Price, t1.Reg_Price),
Sale_Price = coalesce(t3.Price, t1.Sale_Price)
FROM PROD_TB t1
LEFT JOIN
PRICE_TB t2
ON
t1.ProductCode = t2.ProductCode AND
t2.[Type] = 'REG'
LEFT JOIN
PRICE_TB t3
ON
t1.ProductCode = t3.ProductCode AND
t3.[Type] = 'SALE'
WHERE
t2.[Type] = 'REG' OR
t3.[Type] = 'SALE'

Related

How to update data with multi condition

I have a table with 5 columns like this table below:
I wanna fill the approval column based on conditions such as:
APPROVAL = "Y" IN CASE
(1) CUSTOMER_NEW <> CUSTOMER (as in the case CUSTOMER = 12467)
(2) CUSTOMER_NEW = CUSTOMER AND SALE_SHORT_ID COLUMN HAS DIFFERENT VALUE (as in the case CUSTOMER = 13579)
(3) CUSTOMER_NEW = CUSTOMER AND SALE_SHORT_ID HAS THE SAME VALUE THEN MAX(LEN(SALE_ID) (as in the case CUSTOMER = 65465)
ELSE "N"
My result expected to like this table:
Thanks for your support.
I am not sure about all your your conditions but this one could do it:
UPDATE a
SET approval =
CASE WHEN
a.customer <> a.customer_new OR
a.customer = a.customer_new AND b.sale_short_eq = 0 OR
a.customer = a.customer_new AND a.sale_id = b.max_len_sale_id
THEN 'Y'
ELSE 'N'
END
FROM
thetable a
INNER JOIN (
SELECT
customer,
CASE WHEN MIN(sale_short_id) = MAX(sale_short_id) THEN 1 ELSE 0 END AS sale_short_eq,
( SELECT TOP 1 sale_id
FROM thetable
WHERE customer = c.customer
ORDER BY LEN(sale_id) DESC
) AS max_len_sale_id
FROM thetable c
GROUP BY customer
) b
ON a.customer = b.customer
Note that the columns b.sale_short_eq and b.max_len_sale_id are returned by a sub-query joined to the main query.
Especially SALE_SHORT_ID HAS THE SAME VALUE THEN MAX(LEN(SALE_ID) is not clear. Did you mean that SALE_ID must be the same as the maximum length SALE_ID? Because SALE_SHORT_ID cannot be the same than any SALE_ID. And what happens if two different SALE_IDs have the same max length?
See: https://dbfiddle.uk/7Ct87-Mk

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

CASE WHEN 2 results in 1 column have the same result in another column

with the sample data below a collection_ref will carry 3 or 4 movements but the key 2 are the purchase and sale. The supply chain approved will be 1 once the movement is complete.
I want to CASE WHEN the movement is a Sale and Supply Chain Approved is 1 then a new column for all lines that have the same collection ref to show 'Completed' Else 'Outstanding'... any ideas?
Thanks in advance
SELECT DISTINCT a.bulk_type_code,
a.bulk_number,
a.supplier_contract_ref,
a.supplier_consignment_ref,
a.supplier_org_code,
a.supplier_org_name,
a.collection_ref,
a.raw_weight_tons,
a.financial_net_weight_tons,
a.purchase_weight_tons,
a.delivery_date,
b.delivery_term_code,
b.delivery_term_description,
c.week_number
FROM bi.bulk_subcontainer_pricing_group_summary a
LEFT JOIN bi.contracts b ON a.supplier_contract_number = b.contract_number
OR a.purchaser_contract_number = b.contract_number
INNER JOIN bi.weeks c ON a.delivery_date BETWEEN c.start_date AND c.end_date
WHERE a.delivery_date BETWEEN #DFrom AND #DTo
AND a.bulk_type_code IN (#BulkType)
AND a.business_unit_code = 'OLLIMP'
AND a.pricing_type_group_code = #pricing_hidden
ORDER BY a.collection_ref
It would be helpful if you could share the schema instead if writing out the column / key names.
It sounds like what you want is something like this
Select Case when Bulk_Type_Code = 'Sale' and Supply_Chain_Approved = 1 then 'Completed'
when Bulk_Type_Code = 'Sale' and Supply_Chain_Approved = 0 then 'Outstanding'
else NULL end as CalculatedColumn
If the Bulk_Type_Code is not sale, then this column will be null.

Adding columns in result in SQL from one column

First time here so I didn't see a question like this so I hope you can help me.
I am attempting to add 2 columns to a query result.
If aa.actionid = '123', return a result in a column called test1.
Ifaa.actionid = '5', then create a column called this to put the price per ton in that column called either test 1 or test 2
This is what I have so far. I am not really sure if this is right:
SELECT CO.INVOICE_PREFIX
,C.CUSTOMER_NAME
,S.SITE_NAME
,W.DESCRIPTION
,AA.PER_TON_PRICE
,AA.ACTION_ID
,AA.APPLICABLE_ACTION_ID
,OI.VALID_UNTIL
,CON.END_DATE
,CC.DESCRIPTION
,(case when aa.actionid = '123' then aa.per_ton_price Test1
,(case when aa.actionid = '5' then) aa.per_ton_price test2
FROM CUSTOMER C
JOIN SITE S ON C.CUSTOMER_ID = S.CUSTOMER_ID
JOIN CONTRACT CON ON C.CUSTOMER_ID = CON.CUSTOMER_ID
JOIN SITE_ORDER SO ON SO.SITE_ID = S.SITE_ID
JOIN COMPANY_OUTLET CO ON SO.COMPANY_OUTLET_ID = CO.COMPANY_OUTLET_ID
JOIN ORDER_ITEM OI ON OI.ORDER_ID = SO.SITE_ORDER_ID
JOIN PRODUCT P ON OI.PRODUCT_ID = P.PRODUCT_ID
JOIN APPLICABLE_ACTION AA ON AA.ORDER_ITEM_ID = OI.ORDER_ITEM_ID
JOIN COMPETITIVE_CONDITION CC ON CC.COMPETITIVE_CONDITION_ID = OI.COMPETITIVE_CONDITION_ID
LEFT JOIN WASTE W ON W.WASTE_ID = AA.WASTE_ID
JOIN ACTION A ON AA.ACTION_ID = A.ACTION_ID
WHERE AA.ACTION_ID IN ('123','5')
AND P.PRODUCT_ID='2'
AND OI.VALID_UNTIL >= GETDATE()
You will always need to return both columns for all rows. What you can do is map the 'unused' column (dependent on the row data) to a default value, such as null, e.g.:
,case when aa.actionid = '123' then aa.per_ton_price else null end Test1
,case when aa.actionid = '5' then aa.per_ton_price else null end test2
The database is only going to return a TABLE, so if you think about the concept of a Table, could one row have different amount of columns than the others? Probably not. So what you really want to be doing is set the particular column's value to null instead of trying to not output that column at all.

Using query results in further procedcures

I'm fairly new to SQL especially PL/SQL, I have a grasp of the basics but what i'm trying to do goes over my head. This is a small part of a larger system but I will focus on 3 tables Sale_Head, Sale_Line and Product. This work is being done in Orcale SQL developer.
http://imgur.com/OrfhM0g,i4pMnTx - Sale Table
http://imgur.com/OrfhM0g,i4pMnTx#1 - Product Table
(Im a newbie so i dont have enough rep to directly post images)
Im attempting to build up some procedures that process pending sales. Sales have a status in the Sale_Head which can either be p(pending), s(shipped), i(in progress), x(cancelled), or b(back orders). The procedure(s) need to find sales with a pending status (i've got that far in my code), then check the products stock levels are above the minimum level enough to complete the sale. If all these conditions are met pending sales become i (in progress) and if there is inadequate stock it comes backordered (b). I have a general idea of how to go about this, but when it comes having to referencing the product table using the foreign from sale_line I get confused.
--create or replace procedure Process_Products is
--begin
select Sale_Head.Sale_Num , Sale_Line.Product_Code as
from Sale_Head
inner join Sale_Line on
Sale_Head.Sale_Num = Sale_Line.SALE_NUM
where Sale_head.Status = 'P';
--if Sale_Line.Product_Code = Product.Product_Code >
--end;
This returns the product codes for orders that have a pending status, but now I need to check their stock levels in the product table and make adjustments.
Please correct me if I am wrong, but if you are saying "for those sales in a pending status where enough inventory exists to fulfill the order, change the status to i (in progress), otherwise not enough inventory exists, so change the status to b (backordered)", then the following should help:
-- This is a useful query to display what you need - debugging, use in cursor, etc
SELECT sh.Sale_Num, sl.Product_Code, sl.Quantity as QtyToBuy,
p.Stock_Count, p.Minimum_Level,
(Case When sl.Quantity <= p.Minimum_Level Then 'i'
Else 'b' end) as NewStatus
FROM Sale_Head sh
INNER JOIN Sale_Line sl
ON sh.Sale_Num = sl.SALE_NUM
INNER JOIN Product p
ON sl.Product_Code
WHERE Sale_head.Status = 'P';
The status code can be updated in one query if that is what you want:
--This query will actully do the update (if view is updatable)
UPDATE
(
SELECT sh.Status, (Case When sl.Quantity <= p.Minimum_Level Then 'i'
Else 'b' end) as NewStatus
FROM Sale_Head sh
INNER JOIN Sale_Line sl
ON sh.Sale_Num = sl.SALE_NUM
INNER JOIN Product p
ON sl.Product_Code
WHERE sh.Status = 'P'
) a
SET a.Status = a.NewStatus;
If the above view is not updatable, try this syntax:
--Otherwise try this syntax
UPDATE Sale_Head sh1 Set Sale_Head.Status =
SELECT (Case When sl.Quantity <= p.Minimum_Level Then 'i'
Else 'b' end) as NewStatus
FROM Sale_Head sh
INNER JOIN Sale_Line sl
ON sh.Sale_Num = sl.SALE_NUM
INNER JOIN Product p
ON sl.Product_Code
WHERE sh1.Sale_Num = sh.Sale_Num
)
WHERE Sale_Head.Status = 'P';