Is it possible to use AND in an UPDATE SET clause in a CASE statement? - sql

I need to check two conditions:
1. when the function returns true
2. when the function returns true AND ISP_Program has the word "IRSS" in it
What is the correct syntax? I have the following:
UPDATE [PAYROLL].[dbo].[BILL]
SET Pay_Code = CASE dbo.is_Holiday([BILL].Date)
WHEN 1 THEN holiday_code
WHEN 1 AND ISP_Program like '%IRSS%' THEN '66'
ELSE Pay_Code
END
FROM tbl_TXEX_HOLIDAY
INNER JOIN [BILL] ON [BILL].Pay_Code = tbl_HOLIDAY.regular_code

I think you want:
SET Pay_Code = (CASE WHEN dbo.is_Holiday([BILL].Date) = 1 AND ISP_Program like '%IRSS%' THEN '66'
WHEN dbo.is_Holiday([BILL].Date) = 1 THEN holiday_code
ELSE Pay_Code
END)
Note that the ordering of these conditions is important.
I assume that BILL is the table referenced in the UPDATE. I would recommend writing the complete logic as:
UPDATE b
SET Pay_Code = (CASE WHEN dbo.is_Holiday(b.Date) = 1 AND ISP_Program like '%IRSS%' THEN '66'
WHEN dbo.is_Holiday(b.Date) = 1 THEN holiday_code
ELSE b.Pay_Code
END)
FROM [PAYROLL].[dbo].[BILL] b JOIN
tbl_TXEX_HOLIDAY h
ON b.Pay_Code = h.regular_code;
Notes:
Define aliases for the tables so the query is easier to write and to read.
Use the alias for the update, so it is clear what you intend.
Put the table being updated first. After all, it needs to have matching rows for the update to take place.
Of course, fix the case expression.

Related

IF / Case statment in SQL

I have a column where I have 0 or 1. I like to do the following set up:
If 0 than put / use the Region_table (here I have regions like EMEA, AP,LA with finished goods only) and when it 1 then put / use the Plant_table (here I have plants with non-finished goods) data's.
I tried to write it in 2 different statements but it is not good:
,Case
when [FG_NFG_Selektion] = '0' Then 'AC_region'
End as 'AC_region'
,Case
when [FG_NFG_Selektion] = '1' Then 'AC_plant'
End as 'AC_plant'
I'm not 100% clear on what you're looking for, but if you want to get data from different tables based on the value in the [FG_NFG_Selektion] field, you can do something like this:
SELECT
CASE
WHEN [FG_NFG_Selektion] = '0' THEN r.some_col -- If 0, use value from "region" table
WHEN [FG_NFG_Selektion] = '1' THEN p.some_col -- If 1, use value from "plant" table
END AS new_field
FROM MyTable t
LEFT JOIN AC_region r ON t.pk_col = r.pk_col -- get data from "AC_region" table
LEFT JOIN AC_plant p ON t.pk_col = p.pk_col -- get data from "AC_plant" table
;
If [FG_NFG_Selektion] is a numeric field, then you should remove the single quotes: [FG_NFG_Selektion] = 0.
I would strongly recommend putting the conditions in the ON clauses:
SELECT COALESCE(r.some_col, p.some_col) as som_col
FROM t LEFT JOIN
AC_region r
ON t.pk_col = r.pk_col AND
t.FG_NFG_Selektion = '0' LEFT JOIN
AC_plant p
ON t.pk_col = p.pk_col AND
t.FG_NFG_Selektion = '1';
Why do I recommend this? First, this works correctly if there are multiple matches in either table. That is probably not an issue in this case, but it could be in others. You don't want to figure out where extra rows come from.
Second, putting the conditions in the ON clause allows the optimizer/execution engine to take advantage of them. For instance, it is more likely to use FG_NFG_Selektion in an index.

Where clause with a conditional condition

Case: I have a stored procedure in where I got all the information of a table.
I have 2 parameters in order to set the Where clause but one of those could be
0.
Question: How do I do a Case When or an If in my Where clause depending on my parameter value?
I want to apply the where clause only if the value is different from 0
if is 0 I don't want to do it.
Code:
#ID_ORDER,
#ID_SUPPLIER
Select *
From Orders ord
where #ID_SUPPLIER = ord.ID_SUPPLIER
AND CASE WHEN #ID_ORDER = 0 THEN ord.ID_ORDER = #ID_ORDER END
You don't. You just use and and or:
select *
from Orders ord
where ord.ID_SUPPLIER = #ID_SUPPLIER) and
(ord.ID_ORDER = #ID_ORDER or #ID_ORDER = 0);
Note that the logic you are attempting is backwards. This only applies the filter on id_order when the value is not 0.

SQL UPDATE with multiple WHERE (relations) conditions

I would like to know if it is possible to perform such UPDATE in oracle SQL database :
UPDATE mark
SET
mark=
CASE
WHEN mark.val<= 5
THEN val*1.1
ELSE val END
WHERE mark.id_classes = classes.id_classes
AND classes.ID_subject = subject.ID_subject
AND subject.ID_subject = 5;
SQL developer returns error in this part :
WHERE mark.id_classes = classes.id_classes
AND classes.ID_subject = subject.ID_subject
AND subject.ID_subject = 5;
So I guess that it is not possible to make such a complex condition, is it any other way to do that then?
Might be silly to try more SELECT like condition but on the other hand I don't see the reason why it is not working.
You can use a subquery:
UPDATE mark
SET mark = val * 1.1
WHERE mark.val <= 5 AND
EXISTS (SELECT 1
FROM classes c JOIN
subjects s
ON c.ID_subject = s.ID_subject
WHERE mark.id_classes = c.id_classes AND
s.ID_subject = 5
);
Notice that I moved the CASE condition to the WHERE clause so only the rows that need to be updated are updated.
You can't reference another two tables (CLASSES and SUBJECT) just like that, out of nowhere. Here's code which shows how you might have done that:
update mark m set
m.mark = (select case when m.val <= 5 then m.val * 1.1
else m.val
end
from classes c join subject s on c.id_subject = s.id_subject
where c.id_classes = m.id_classes
and s.id_subject = 5
)
where ...
As you didn't use table aliases within CASE, I don't know which table the VAL column belongs to (so I presumed it is MARK).
Also, UPDATE itself might need the WHERE clause which would restrict number of rows to be updated.
I find that in cases like this a MERGE statement is easier to understand:
MERGE INTO MARK m
USING (SELECT c.ID_CLASSES
FROM CLASSES c
WHERE c.ID_SUBJECT = 5) d
ON (m.ID_CLASSES = d.ID_CLASSES)
WHEN MATCHED THEN
UPDATE SET m.MARK = CASE
WHEN m.VAL <= 5
THEN m.VAL * 1.1
ELSE
m.VAL
END
Or, since the ID_SUBJECT is a constant, you can simplify your update to
UPDATE MARK m
SET m.MARK = CASE
WHEN m.VAL <= 5
THEN m.VAL * 1.1
ELSE
m.VAL
END
WHERE m.ID_CLASSES = 5
Best of luck.

Update column within CASE statement with results of a subquery postgres

I need to update a column based on the results of a subquery. If the subquery returns results for that column then the columns must be updated, is the query returns no results for that column then I need to update with 0.
I do not know where to place the subquery and how to combine it with the CASE statement. This is what I thought but the syntax is not correct. Can anybody help please?
(SELECT datazones.ogc_fid, count(*) as total
FROM suppliersnew suppliers, datazone_report_resupply datazones
WHERE St_contains(datazones.geom, suppliers.geometry) AND (suppliers.status = 'Under construction' OR
suppliers.status = 'Unknown' OR suppliers.status = 'Operational') GROUP by datazones.ogc_fid ORDER BY total ASC) sources
UPDATE datazone_report_resupply
SET es_actual =
CASE
WHEN datazone_report_resupply.ogc_fid = sources.ogc_fid THEN sources.total
ELSE 0
END
The query is a little hard to follow, because the aggregation is on the outer column (this is unusual). However, you don't need aggregation or order by. You only seem to care whether a row exists.
I think the logic is:
UPDATE datazone_report_resupply r
SET es_actual =
(CASE WHEN EXISTS (SELECT 1
FROM suppliersnew s
WHERE St_contains(r.geom, s.geometry) AND
s.status IN ('Under construction', 'Unknown', 'Operational')
)
THEN 1 ELSE 0
END);

group by clause issue

I have written a query in access and now I am trying to write the same in SQL Server I am getting following error:
Msg 164, Level 15, State 1, Procedure OQRY_STEP_1_1, Line 15
Each GROUP BY expression must contain at least one column that is not an outer reference.
My SQL Query is as follows:
SELECT
ns11.SYS_ID,
ns11.SUB_NET_ID,
ns11.TEMP_ID,
ns11.EQ_ID,
ns11.NODE_NAME,
ns11.EQ_NAME,
ns11.VAR_NAME,
ns11.VAR_SET,
ns11.VAR_SUBSET,
ns11.EQ_TYPE,
ns11.RHS_RELN,
ns11.RHS_OBJECT,
ns11.EQ_TP_OFFSET,
ns11.RHS_TP_OFFSET,
ns11.RETAIN,
nmte.RHS_VAR_SET,
nmte.RHS_VAR_SUBSET,
nmte.RHS_VAR_NAME,
0 AS RHS_VAR_TYPE,
CASE
WHEN [asp].[VALUE] = NULL THEN 0
ELSE [asp].[VALUE]
END RHS_VALUE
INTO ##OT_STEP_1_1
FROM (##NT_STEP_1_1 ns11
INNER JOIN ##NT_MASTER_TEMP_EQUATION nmte
ON (ns11.SYS_ID = nmte.SYS_ID)
(ns11.SUB_NET_ID = nmte.SUB_NET_ID)
AND (ns11.TEMP_ID = nmte.TEMP_ID)
AND (ns11.EQ_ID = nmte.EQ_ID)
AND (ns11.NODE_NAME = nmte.NODE_NAME)
AND (nmte.SYS_ID = ns11.SYS_ID)
AND (nmte.SUB_NET_ID = ns11.SUB_NET_ID))
LEFT JOIN AMST_SIM_PAR asp ON
(nmte.SYS_ID = asp.SYS_ID)
AND (nmte.SUB_NET_ID = ns11.SUB_NET_ID)
AND (nmte.RHS_VAR_NAME = asp.VAR_NAME)
GROUP BY
ns11.SYS_ID,
ns11.SUB_NET_ID,
ns11.TEMP_ID,
ns11.EQ_ID,
ns11.NODE_NAME,
ns11.EQ_NAME,
ns11.VAR_NAME,
ns11.VAR_SET,
ns11.VAR_SUBSET,
ns11.EQ_TYPE,
ns11.RHS_RELN,
ns11.RHS_OBJECT,
ns11.EQ_TP_OFFSET,
ns11.RHS_TP_OFFSET,
ns11.RETAIN,
nmte.RHS_VAR_SET,
nmte.RHS_VAR_SUBSET,
nmte.RHS_VAR_NAME,
0,
CASE
WHEN [asp].[VALUE] = NULL THEN 0
ELSE [asp].[VALUE]
END
ORDER BY
CASE
WHEN [asp].[VALUE] = NULL THEN 0
ELSE [asp].[VALUE]
END;
I am not sure why it is not taking 0 in the group by clause?
I think the GROUP BY ..., 0, ... is the issue here. Try removing that 0 from there. There is no point grouping by a constant.
Sidenote:
CASE WHEN [AMST_SIM_PAR].[VALUE] = NULL
THEN 0
ELSE [AMST_SIM_PAR].[VALUE]
END
should be be written with IS NULL instead of = NULL or as:
COALESCE( [AMST_SIM_PAR].[VALUE], 0 )
I think the constant '0' in your group by is the problem.
Are you using ANSI_NULLS? SQL-92 defines "= NULL" or "<> NULL" to always return false. Try changing "= NULL" to "IS NULL".
Also in your left join you have a criteria that doesn't match the outer table. The inner join already links SUB_NET_ID on those two tables so you can remove it from your left join.
Since you are not taking any aggregates, why not just use DISTINCT instead of repeating all that noise in the GROUP BY? Also the ORDER BY is not very useful because you are using SELECT INTO, which creates a new table, which by definition is an unordered set of rows. In order to get the data out of that table in the right "order" you should use an ORDER BY when you eventually select out of it. If you want the data optimized for joins or what have you after the table is created, create a clustered index after the SELECT INTO. Finally, why are you using ##global temp tables? You know that two users can't execute this code at the same time, right?
All that said, here is a much simpler and easier to read version:
SELECT DISTINCT
n.SYS_ID,
n.SUB_NET_ID,
n.TEMP_ID,
n.EQ_ID,
n.NODE_NAME,
n.EQ_NAME,
n.VAR_NAME,
n.VAR_SET,
n.VAR_SUBSET,
n.EQ_TYPE,
n.RHS_RELN,
n.RHS_OBJECT,
n.EQ_TP_OFFSET,
n.RHS_TP_OFFSET,
n.RETAIN,
te.RHS_VAR_SET,
te.RHS_VAR_SUBSET,
te.RHS_VAR_NAME,
RHS_VAR_TYPE = 0,
RHS_VALUE = COALESCE(a.VALUE, 0)
INTO ##OT_STEP_1_1
FROM ##NT_STEP_1_1 AS n
INNER JOIN ##NT_MASTER_TEMP_EQUATION AS te
ON n.SYS_ID = te.SYS_ID
AND n.SUB_NET_ID = te.SUB_NET_ID
AND n.TEMP_ID = te.TEMP_ID
AND n.EQ_ID = te.EQ_ID
AND n.NODE_NAME = te.NODE_NAME
AND te.SYS_ID = n.SYS_ID
AND te.SUB_NET_ID = n.SUB_NET_ID
LEFT OUTER JOIN dbo.AMST_SIM_PAR AS a
ON te.SYS_ID = a.SYS_ID
AND te.SUB_NET_ID = n.SUB_NET_ID
AND te.RHS_VAR_NAME = a.VAR_NAME;