Conditional update either column1 or column2 or column3 - sql

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

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

Convert multiple rows to columns but as one rows

How do i achieve achieve all this records under one row since every employee has one of each NHIF, NSSF and KRA number?
Below is the query i used but the all appear separate rows.
SELECT DISTINCT
hrmemployeehdr.employeeslno,
hrmemployeehdr.employeecode,
hrmemployeehdr.employeefirstname,
hrmemployeehdr.employeemiddlename,
hrmemployeehdr.employeelastname,
hrmDesignationHdr.DesignationName,
hrmemployeehdr.DateOfBirth,
hrmemployeehdr.DateOfJoin,
hlocationhdr.locationname,
hrmEmployeeIdentityDtl.IDProofReferenceNo AS [National ID],
(CASE
WHEN hrmEmployeeDeductionSettingsDtl.DeductionCode = 1 THEN hrmEmployeeDeductionSettingsDtl.EmployeeRegID
ELSE ''
END) AS NHIF,
(CASE
WHEN hrmEmployeeDeductionSettingsDtl.DeductionCode = 2 THEN hrmEmployeeDeductionSettingsDtl.EmployeeRegID
ELSE ''
END) AS NSSF,
(CASE
WHEN hrmEmployeeDeductionSettingsDtl.DeductionCode = 3 THEN hrmEmployeeDeductionSettingsDtl.EmployeeRegID
ELSE ''
END) AS KRA,
hrmemployeestatusdtl.Email AS [Employee Email],
huser.email AS [User Account Email],
hrmEmployeeGradeHdr.GradeName,
hDepartment.DepartmentName
FROM hrmemployeehdr
JOIN hrmemployeestatusdtl ON hrmemployeestatusdtl.employeeslno = hrmemployeehdr.employeeslno
JOIN hdivision ON hdivision.divisioncode = hrmemployeestatusdtl.divisioncode
JOIN hlocationhdr ON hlocationhdr.locationcode = hrmemployeestatusdtl.workinglocationcode
JOIN hDepartment ON hDepartment.DepartmentCode = hrmemployeestatusdtl.DepartmentCode
JOIN hrmDesignationHdr ON hrmDesignationHdr.DesignationCode = hrmemployeestatusdtl.DesignationCode
JOIN hrmEmployeeCategoryHdr ON hrmEmployeeCategoryHdr.CategoryCode = hrmemployeestatusdtl.CategoryCode
JOIN hrmEmployeeGradeHdr ON hrmEmployeeGradeHdr.GradeCode = hrmemployeestatusdtl.GradeCode
LEFT JOIN huser ON huser.employeeslno = hrmemployeehdr.employeeslno
JOIN hMasterValue ON hMasterValue.MasterValueID = hrmemployeestatusdtl.MasterValue_EmploymentStatusID
JOIN hrmEmployeeIdentityDtl ON hrmEmployeeIdentityDtl.EmployeeSlno = hrmemployeehdr.EmployeeSlno
INNER JOIN hMasterValue a ON a.MasterValueID = hrmEmployeeIdentityDtl.MasterValue_IDProofTypeID
INNER JOIN hrmEmployeeDeductionSettingsDtl ON hrmEmployeeDeductionSettingsDtl.EmployeeSlno = hrmemployeehdr.EmployeeSlno
LEFT JOIN hrmDeductionHdr ON hrmDeductionHdr.DeductionCode = hrmEmployeeDeductionSettingsDtl.DeductionCode
WHERE hrmemployeestatusdtl.employeeslno NOT IN (SELECT hrmemploymentstoppageandtermination.employeeslno
FROM hrmemploymentstoppageandtermination)
AND hrmEmployeeIdentityDtl.MasterValue_IDProofTypeID = 2741005
--and hrmemployeestatusdtl.email = huser.email
--and huser.isemployee = 1
-- select * from huser
ORDER BY employeefirstname ASC;
Use conditional aggregation on the detail table to condense all those rows into one for each employee. Something like:
with edet as (select employeeslno,
max(CASE DeductionCode when 1 THEN EmployeeRegID ELSE '' END) AS NHIF,
max(CASE DeductionCode when 2 THEN EmployeeRegID ELSE '' END) AS NSSF,
max(CASE DeductionCode when 3 THEN EmployeeRegID ELSE '' END) AS KRA
from dbo.hrmEmployeeDeductionSettingsDtl
group by employeeslno)
select emp.employeeslno, ...,
edet.NHIF, edet.NSSF, edet.KRA, ...
from dbo.hrmemployeehdr as emp
inner join edet on emp.employeeslno = edet.employeeslno
...
order by ...
;
Notice the formatting changes that HELP everyone read and understand the code as well as the good habits of using aliases, schema-qualified table names, statement terminator, etc. As already mentioned, the other joins might be contributing to the problem - but this addresses the 1:3 relationship between the header and detail table.

Trying to Update Case When Then, based on matching IDs in two tables

I am trying to updated IDs in a table named Price, based on matches of IDs in a table named CW. Here is the SQL that I'm testing.
UPDATE Price
SET ISN = (case when CW.id_cd = 'ISN' THEN CW.id_number else ISN end),
SED = (case when CW.id_cd = 'SED' THEN CW.id_number else SED end),
CSP = (case when CW.id_cd = 'CSP' THEN CW.id_number else CSP end)
FROM CW
WHERE Price.ID_GLOBAL = CW.asset_id
Here is a screen shot of the two schemas. So, now the values in the yellow cells are missing IDs, but I'm trying to get them filled in with the values I'm showing here.
The weird thing is that most of the IDs in the Price table are updated fine, based on the same IDs in the CW table, but not all IDs are being updated. After doing the above update, when I run the SQL below, I get a bunch of records returned, but I would expect no records at all because all CSP (IDs) should have been updated in the Price table.
Select *
From Price
INNER JOIN CW
ON Price.id_global = CW.asset_id
Where Price.CSP IS NUll
AND CW.id_cd = 'CSP'
I think you have multiple rows in CW for each ID_GLOBAL. The problem is that only one matching row gets used. The solution is either a series of LEFT JOINs or pre-aggregation:
UPDATE Price
SET ISN = COALESCE(cw.isn, price.isn),
SED = COALESCE(cw.sed, price.sed),
CSP = COALESCE(cw.csp, price.csp)
FROM (SELECT asset_id,
MAX(case when CW.id_cd = 'ISN' THEN CW.id_number END) as ISN,
MAX(case when CW.id_cd = 'SED' THEN CW.id_number END) as SED,
MAX(case when CW.id_cd = 'CSP' THEN CW.id_number END) as CSP
FROM CW
GROUP BY asset_id
) cw
WHERE Price.ID_GLOBAL = CW.asset_id;
Note: This assumes that the new values are not ever NULL. If that is a possibility, the assignment logic needs to take that into account. I am guessing that complication is unnecessary.
EDIT:
Do this in three steps. For 'ISN':
UPDATE Price
SET ISN = cw.isn
FROM CW
WHERE Price.ID_GLOBAL = CW.asset_id AND
CW.id_cd = 'ISN';
I am guessing the COALESCE() is not necessary.

SQL Case Update to two different column based on select

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'

Trouble Aggregating Rows with SQL Statement

I am attempting to pivot some data out of the Vendor column in this table, creating new columns for each of my vendors. Ideally, I would have 1 row for each ContractDate, and then 2 values. However, I'm ending up with 2 rows of a distinct ContractDate.
I believe i may need some sort of temp table query to do this...i'm not sure though.
SELECT [ContractDate],
CASE WHEN Vendor = 'AirDat'
THEN (sum(wf.Temppop) / sum(wf.Population)) END as 'AirDat',
CASE WHEN Vendor = 'CWG'
THEN (sum(wf.Temppop) / sum(wf.Population)) END as 'CWG'
FROM [ECPDB].[dbo].[weather.forecast] as wf
INNER JOIN ecpdb.[lookup].[newWeatherStation] as ws
ON wf.[Station_ID] = ws.[Station ID]
INNER JOIN ecpdb.[lookup].[CountyNew] as c
ON ws.[County FIPS] = c.[County FIPS]
WHERE tradedate = '7/2/2012'
AND [BENTEK Cell] = 'Northeast'
GROUP BY [ContractDate], vendor
You can do this using a subquery;
Select ContractDate,
max(case when Vendor = 'AirDat' THEN Vendor_Average End) as AirDAT,
max(case when Vendor = 'CWG' THEN Vendor_Average End) as CWG
from (
SELECT [ContractDate] , Vendor, (sum(wf.Temppop) / sum(wf.Population)) as Vendor_Average
FROM [ECPDB].[dbo].[weather.forecast] as wf
inner join ecpdb.[lookup].[newWeatherStation] as ws
on wf.[Station_ID] = ws.[Station ID]
inner join ecpdb.[lookup].[CountyNew] as c
on ws.[County FIPS] = c.[County FIPS]
where tradedate = '7/2/2012' and [BENTEK Cell] = 'Northeast'
group by ContractDate, Vendor
) as Subquery
group by Contractdate
This way, the query runs and finds the values you need, and then you pick the rows you want without needing to group.