Case in update statement - sql

I am trying to translate a talend code which has a nested IF statement into SQL
I thought I had translated it correctly, but no records are getting updated since the join condition fails. I added a top level case statement to check for existence of records, but wanted to double check from the experts here if my translation is correct at all.
Logic from Talend Mapper:
IF row32.DISPLAY_NAME_REPORTED IS NULL THEN
IF row31.REPORTED_DISPLAY_NAME IS NULL THEN
IF row87.SPEC_TYPE1 IS NULL THEN
IF row87.SPEC_TYPE2 IS null THEN
row34.Series
ELSE
row34.Series + row34.Type2
END
ELSE
row34.Series + row34.Type2
END
ELSE
row31.REPORTED_DISPLAY_NAME
END
ELSE
row32.DISPLAY_NAME_REPORTED
END
Corresponding case statement in SQL:
update a
set a.seriesbt = case when exists (select 1 from row32 x where
x.delivery_fk = a.delivery_fk) then
case when b.delivery_fk is not null and
b.DISPLAY_NAME_REPORTED is null then
case when c.reported_display_name is null then
case when d.SPEC_TYPE1 is null then
case when d.SPEC_TYPE2 is null then
a.series
else
a.series+a.SPEC_TYPE2 end
else a.series + a.SPEC_TYPE1 end
else c.reported_display_name end
else b.DISPLAY_NAME_REPORTED end
else a.series end
from tmpSales a
left join row32 b on b.delivery_fk = a.delivery_fk
left join row31 c on c.DELIVERY_FK = a.delivery_fk
left join row87 d on d.DELIVERY_FK = a.delivery_fk
Question is: Did I translate the talend mapper logic into SQL correctly? If not, can you please tell me what is wrong.
Should I be include "when exists" for each table?
I thought the left join should implicitly handle it.

You seem to have added an additional condition that was not in your original code. Coding the opposite way can make things simpler and avoid nested CASE expressions.
I changed your table alias to make it easier to understand where the columns come from without having to go back to the FROM clause.
UPDATE s
SET a.seriesbt = CASE WHEN r32.DISPLAY_NAME_REPORTED IS NOT NULL THEN r32.DISPLAY_NAME_REPORTED
WHEN r31.reported_display_name IS NOT NULL THEN r31.reported_display_name
WHEN r87.SPEC_TYPE1 IS NOT NULL THEN s.series /*row34.Series*/ + s.SPEC_TYPE1
WHEN r87.SPEC_TYPE2 IS NULL THEN s.series --row34.Series
ELSE s.series /*row34.Series*/ + s.SPEC_TYPE2
END
FROM tmpSales s
LEFT JOIN row32 r32 ON r32.delivery_fk = s.delivery_fk
LEFT JOIN row31 r31 ON r31.DELIVERY_FK = s.delivery_fk
LEFT JOIN row87 r87 ON r87.DELIVERY_FK = s.delivery_fk;
I just realized that it could be simplified even more.
UPDATE s
SET a.seriesbt = COALESCE( r32.DISPLAY_NAME_REPORTED,
r31.reported_display_name,
s.series /*row34.Series*/ + s.SPEC_TYPE1,
s.series /*row34.Series*/ + s.SPEC_TYPE2,
s.series --row34.Series
)
FROM tmpSales s
LEFT JOIN row32 r32 ON r32.delivery_fk = s.delivery_fk
LEFT JOIN row31 r31 ON r31.DELIVERY_FK = s.delivery_fk
LEFT JOIN row87 r87 ON r87.DELIVERY_FK = s.delivery_fk;

Related

Condition if sql

I have this query
SELECT
SI_Num_Inventario = COALESCE (t.SI_Num_Inventario, c.SI_Num_Inventario),
SI_Ubicacion = COALESCE(t.SI_Ubicacion, c.SI_Ubicacion),
SI_Ubicacion_Fisica = COALESCE(t.SI_Ubicacion_Fisica, c.SI_Ubicacion_Fisica),
SI_Num_Articulo = COALESCE(t.SI_Articulo, c.SI_Num_Articulo),
NULL,
SI_Num_Conteo = COALESCE(cs.SI_Num_Conteo,2),
GETDATE(),
'Admin',
c.SI_OV
FROM
SI_Inventario_Teorico_QAD t
FULL JOIN
SI_Conteo c ON t.SI_Articulo = c.SI_Num_Articulo
AND t.SI_Ubicacion = c.SI_Ubicacion
INNER JOIN
SI_Maestro_Ref_QAD m ON t.SI_Articulo = m.SI_Num_Articulo
OR c.SI_Num_Articulo = m.SI_Num_Articulo
FULL JOIN
SI_Consecutivo cs ON c.SI_Num_Inventario = cs.SI_Num_Inventario
AND cs.SI_Estado = 0
WHERE
c.SI_Num_Articulo = 201423 OR t.SI_Articulo = 201423
And I'm trying to tell you that if c.SI_OV IS NULL INSERT THIS `INSERT INTO``
IF c.SI_OV IS NULL
INSERT INTO SI_Conteo(SI_Num_Inventario, SI_Ubicacion,SI_Num_Articulo, SI_Cantidad,SI_Num_Conteo,SI_Fecha_Conteo, SI_Usuario,SI_OV)
And if it is not NULL insert me this other
ELSE
INSERT INTO SI_Conteo(SI_Num_Inventario, SI_Ubicacion_Fisica, SI_Num_Articulo, SI_Cantidad,SI_Num_Conteo,SI_Fecha_Conteo, SI_Usuario,SI_OV)
END IF;
In short: the CASE construct needs to "live" in your SELECT clause of you SQL statement. The receiving INSERT clause should always mention both column names like this
INSERT INTO SI_CONTEO (SI_Num_Inventario,
SI_Ubicacion, SI_Ubicacion_fisico,
SI_Num_Articulo, SI_Cantidad,SI_Num_Conteo,
SI_Fecha_Conteo, SI_Usuario,SI_OV)
SELECT SI_Num_Inventario = COALESCE (t.SI_Num_Inventario,c.SI_Num_Inventario),
SI_Ubicacion = CASE WHEN SI_OV IS NULL THEN COALESCE(t.SI_Ubicacion, c.SI_Ubicacion) END,
SI_Ubicacion_Fisica = CASE WHEN NOT SU_OV IS NULL THEN COALESCE(t.SI_Ubicacion_Fisica, c.SI_Ubicacion_Fisica) END,
SI_Num_Articulo = COALESCE(t.SI_Articulo, c.SI_Num_Articulo),
NULL, ...
if else in non query language ~= CASE WHEN cond1 ELSE cond2 END in SQL
Use the below query:
INSERT INTO SI_Conteo(SI_Num_Inventario,SI_Ubicacion,SI_Ubicacion_Fisica,SI_Num_Articulo, SI_Cantidad,SI_Num_Conteo,SI_Fecha_Conteo,
SI_Usuario,SI_OV)
SELECT
SI_Num_Inventario = COALESCE (t.SI_Num_Inventario,c.SI_Num_Inventario),
(CASE WHEN c.SI_OV IS NULL THEN COALESCE(t.SI_Ubicacion, c.SI_Ubicacion) ELSE NULL END)AS SI_Ubicacion,
(CASE WHEN c.SI_OV IS NOT NULL THEN COALESCE(t.SI_Ubicacion_Fisica, c.SI_Ubicacion_Fisica) ELSE NULL END)AS SI_Ubicacion_Fisica,
SI_Num_Articulo = COALESCE(t.SI_Articulo, c.SI_Num_Articulo),
NULL,
SI_Num_Conteo = COALESCE(cs.SI_Num_Conteo,2),
GETDATE(),
'Admin',
c.SI_OV
FROM SI_Inventario_Teorico_QAD t
full JOIN SI_Conteo c
ON t.SI_Articulo = c.SI_Num_Articulo
AND t.SI_Ubicacion = c.SI_Ubicacion
INNER JOIN SI_Maestro_Ref_QAD m
ON t.SI_Articulo = m.SI_Num_Articulo
OR c.SI_Num_Articulo = m.SI_Num_Articulo
FULL JOIN SI_Consecutivo cs
ON c.SI_Num_Inventario = cs.SI_Num_Inventario
AND cs.SI_Estado = 0
WHERE c.SI_Num_Articulo = 201423 OR t.SI_Articulo = 201423
Basicallly I have combined both inserts into one Insert, which includes both of the columns , where you want a switch based on Case. Only one column out of SI_Ubicacion and SI_Ubicacion_Fisica will be set based on s.SI_OV value. Hope you got what I am saying,.
Note: I Could not execute this as I don't have any table structure/data with me. I have modified your query manually and posted it here.
Clarify your question. You have a select statement that returns a resultset of some number of rows. You propose to insert them into a table. You claim to need to use if/else (or similar) but it is not clear why. Your proposed insert statements differ by a single column - is that correct? If so, then you probably need to use 2 different insert statements - one to handle the non-null situation and one to handle the null situation. You cannot dynamically change the column list of the inserted table.
OTOH, perhaps you just want to swap the value inserted into the SI_Ubicacion column of the SI_Conteo table? If so, you can probably use isnull or coalesce in the select statement (much like you do now - just differently).

UPDATE statement not working for certain columns in SQL Sever

I had an update statment in a stored proc. which was not updating any records. Hence I broke the update statement into two parts as mentioned below -
the first update runs successfully but the second update is not updating any tax_id record with the same join condition and matches. I am not sure if the issue is with IN operator usage in the CASE statement or whatnot. Can anybody help?
UPDATE s
SET s.is_updated = '1'
,s.update_dt = GETDATE()
,s.update_source = 'ECM'
,s.party_type =
CASE
WHEN e.ClassificationType is not null THEN e.ClassificationType
ELSE s.party_type
END
FROM staging_cust_acct s
right join MTB_AML.dbo.tb_party_kyc e
on s.party_key = e.CustomerInternalID
UPDATE s
SET s.is_updated = '1'
,s.update_dt = GETDATE()
,s.update_source = 'ECM'
,s.tax_id =
case
when s.party_type IN ('Individual-Retail','Individual-High Net Worth') then e.TaxIndividualID
when s.party_type IN ('Corp-Publicly Traded','FI-MSB'
,'Corp-NFP/NGO','Corp-Personal/Non-Operating (WHV)'
,'Corp-Not Publicly Traded/Operating')
then e.TaxEntitiesID
when s.party_type = 'Government' then null
else s.tax_id end
FROM staging_cust_acct s
right join MTB_AML.dbo.tb_party_kyc e
on s.party_key = e.CustomerInternalID
I was trying to update the table on LEFT side of the join using the RIGHT join. Converting the join to LEFT OUTER JOIN worked fine. Moral of the story - Never use RIGHT join :)
UPDATE s
SET s.is_updated = '1'
,s.update_dt = GETDATE()
,s.update_source = 'ECM'
,s.tax_id =
case
when s.party_type IN ('Individual-Retail','Individual-High Net Worth') then e.TaxIndividualID
when s.party_type IN ('Corp-Publicly Traded','FI-MSB'
,'Corp-NFP/NGO','Corp-Personal/Non-Operating (WHV)'
,'Corp-Not Publicly Traded/Operating')
then e.TaxEntitiesID
when s.party_type = 'Government' then null
else s.tax_id end
FROM staging_cust_acct s
left outer join MTB_AML.dbo.tb_party_kyc e
on s.party_key = e.CustomerInternalID

I am trying to replace an EXIST because its inefficient, but I am coming up with different results. Why?

So I have this query that runs an exist statement, but then when I went to replace it, it didn't return the same number of values for 'Suspended with Audit, EIC Watch'
It actually returned less.
The old portion of code is in the comments, the new code is directly after it.
SELECT t.flngKey AS flngTaskKey,
t.fstrAccountType,
t.fstrTaskSource,
CASE t.fstrCategory
WHEN '' THEN ''
ELSE t.fstrTaskSource + '_CAT_' + t.fstrCategory
END AS fstrCategory,
This is the old portion
CASE
--WHEN t.fstrType = '' THEN ''
--WHEN wd.fstrWorkType = 'SUSIN1'
--AND wd.fstrOwner = ' '
--AND wd.flngworkkey = wr.flngworkkey
--AND wr.fstrAccountType <> '007'
--AND wr.fblnOpen = 1
--AND Exists
-- (SELECT 1
-- FROM tblIndicator id
-- WHERE id.fstrIndicator = 'EIWTCH'
-- AND id.flngVer=0
-- --AND fdtmCease > #pdtmRunDate
-- AND id.flngAccountKey = wd.flngAccountKey)
--THEN 'Suspended for Audit Indicator - EIC Watch For'
--ELSE t.fstrTaskSource + '_TYP_' + t.fstrType
--END AS fstrType,
This is the new
CASE
WHEN t.fstrType = '' THEN ''
WHEN wd.fstrWorkType = 'SUSIN1'
AND wd.fstrOwner = ' '
AND wd.flngworkkey = wr.flngworkkey
AND wr.fstrAccountType <> '007'
AND wr.fblnOpen = 1
AND id.fstrIndicator = 'EIWTCH'
AND id.flngVer=0
AND id.flngAccountKey = wd.flngAccountKey
THEN 'Suspended for Audit Indicator - EIC Watch For'
ELSE t.fstrTaskSource + '_TYP_' + t.fstrType
END AS fstrType,
the last part is the same for both (i know its kind of redundant)
FROM tblTaskOpen t with (nolock) LEFT OUTER JOIN tblWorkDetail wd
ON t.flngKey=wd.flngWorkKey LEFT OUTER JOIN tblIndicator id
ON t.flngAccountKey=id.flngAccountKey AND id.fstrIndicator='EIWTCH' AND id.flngVer=0,
tblWorktoReturn wr with (nolock) LEFT OUTER JOIN tblReturn r with (nolock)
ON wr.flngReturnKey = r.flngReturnKey
AND r.flngVer = 0,
t2
WHERE t.fstrCategory = 'RTNCOR'
AND wr.flngWorkKey = t.flngKey
AND t.fstrCategory = t2.fstrCategory
AND t.fstrType = t2.fstrType
In either case, I ended up setting fstrIndicator to the EIWTCH and also flngVer to 0, which should limit the number of records that join with "t" anyways.
What is going on in this EXISTS that is returning more records?
Thanks for all the help!
Those two queries are not the same. First of all, you're using LEFT OUTER JOIN between tblTaskOpen t and tblWorkDetail wd. This will return only those records from tblWorkDetail wd that meet t.flngKey=wd.flngWorkKey (and all other records from tblTaskOpen t but that is not important here).
So the old query has EXISTS which doesn't reference tblTaskOpen t at all. It means it checks existence for even those records in tblWorkDetail wd that are not eventually returned. Hence this EXISTS may return true for more records that straight checking columns of in the new query.

Extracting null fields in SQL Server

I will try to be as detailed as possible. Our corporate controller has asked me for some information regarding our suppliers. Here are the tables:
spp = supplier table, each supplier has one record, there are 5,222 records
ast = supplier account profile, there is a (M, 1) relationship between this table and spp, there are 8,950 records in this table. Each duplicate spp_id has a different atp_id which is a transaction profile.
crt = bank account information, a supplier may or may not have bank account info
xvd = table of checking tables, xvd.xcd_id is the field that holds the checking table id. Checking table 0007 is the table that contains the discount info.
Here is my script:
select spp.spp_id supp_num,
spp.spp_matchname supp_name,
case when spp.spp_ddcalculation = 0
then 'End of Month'
else
case when spp.spp_ddcalculation = 1
then 'Net'
else
case when spp.spp_ddcalculation = 2
then 'End of 10, 20, 30'
else
case when spp.spp_ddcalculation = 3
then 'End of 15 or 30'
else null
end
end
end
end calculation1,
convert(varchar(2), spp.spp_ddduration) + case when spp.spp_ddmd = 0
then ' Days'
else case when spp.spp_ddmd = 1
then ' Months'
else null
end
end duration1,
spp.spp_ddday stop_day1,
xvd.xvd_desc discount,
crt.crt_name bank,
case when ast.ast_ddcalculation = 0
then 'End of Month'
else
case when ast.ast_ddcalculation = 1
then 'Net'
else
case when ast.ast_ddcalculation = 2
then 'End of 10, 20, 30'
else case when ast.ast_ddcalculation = 3
then 'End of 15 or 30'
else null
end
end
end
end
calculation2,
convert(varchar(2), ast.ast_ddduration) + case when ast.ast_ddmd = 0
then ' Days'
else case when ast.ast_ddmd = 1
then ' Months'
else null
end
end
duration2,
ast.ast_ddday stop_day2
from spp left join ast on spp.spp_id = ast.spp_id
left join crt on ast.crt_id = crt.crt_id
inner join xvd on ast.cfd_id = xvd.xcv_id
where xvd.xcd_id = '0007'
and xvd.lng_id = 0
order by spp.spp_id
The problem is that there are 371 records in the ast table that have a non null cfd_id which is the field that relates to the discount in checking table 0007. When I run this I get 371 records, but I need all suppliers, even those with null discounts. I know the problem is a combination of my joins and the fact that there is not a null xcv_id in checking table 0007. Can anyone see anything glaring that I have overlooked?
To recap, there are 8,950 records in ast, but only 371 of them have a non null cfd_id. I need to grab all 8,950 records, I can't seem to extract the null discounts. I think I can probably pull everything into a temp table then grab the discounts, but am wondering if there is a way to do this in one select statement.
Thanks
Tony
Edit: The last line of my from statement seems to be the primary issue
inner join xvd on ast.cfd_id = xvd.xcv_id
There are no null xcv_id but there are null cfd_id. Is there another way to join those two tables, besides checking for equality?
Forgot to mention, we are on SQL Server 2008 R2.
Does this solve the problem ?
FROM spp
LEFT JOIN ast
ON spp.spp_id = ast.spp_id
LEFT JOIN crt
ON ast.crt_id = crt.crt_id
INNER JOIN xvd
ON xvd.xcv_id = ast.cfd_id
WHERE xvd.xcd_id = '0007'
AND xvd.lng_id = 0
I think you can just change your inner join to a left join:
from spp left join ast on spp.spp_id = ast.spp_id
left join crt on ast.crt_id = crt.crt_id
inner join xvd on ast.cfd_id = xvd.xcv_id
to
from spp left join ast on spp.spp_id = ast.spp_id
left join crt on ast.crt_id = crt.crt_id
left join xvd on ast.cfd_id = xvd.xcv_id
If you are saying that you want to select records where xvd.xcd_id is 0007 or null then change your where clause to this:
(xvd.xcd_id = '0007' OR xvd.xcd_id is null)
This sounds like a perfect use for views. Instead of trying to build one complex query, you could build a series of views that build upon one another filtering the data the way you want it... then apply the final query to the last view.

SQL Syntax Help - Update

I have some code like this:
Update table_name
set
[column] = case when d.data is null, then null else d.columnname end.
from...
etc
My question is, how do I set up a function where the 'else d.columnname' is to sum up several columns from joins.
Would it be something like:
...then null else sum(d.column1 + rf.column2 + rwf.column3) as tempcolumn end,
or
...then null else (d.column1 + rf.column2 + rwf.column3) end,
What is the correct way to do a column sum in this set situation?
You can simply do:
update MyTable
set column =
case
when d.data is not null
then d.column1 + rf.column2 + rwf.column3
end
from ...
CASE will return NULL by default when there is no match.
Something like this should work:
UPDATE table_name
SET [column] = CASE WHEN d.data IS NULL
THEN null
ELSE (d.column1 + rf.column2 + rwf.column3)
END
FROM table_name
INNER JOIN other_table1 d ON ...
INNER JOIN other_table2 rf ON ...
INNER JOIN other_table3 rwf ON ...
Of course, in the query above you have to put in the correct relations between the tables in the INNER JOIN - ON clauses