SQL Case statement /where clause issues - sql

I am trying to dynamically modify my where clause by using a declared variable in a case statement above. Forgive me if there is a simple answer to this that I'm missing, but I'm entirely self taught and still have a lot to learn. Here's a sample of the syntax. I am not going to bother with the entire syntax of the statement, just enough that hopefully you will understand what I'm trying to do.
declare #myvar1 double
declare #myvar2 double
SELECT
q1.host_po_nbr,
q1.etd,
CASE
WHEN WEEKDAY(TODAY) = 1 Then 11
WHEN WEEKDAY(TODAY) = 2 Then 12
WHEN WEEKDAY(TODAY) = 3 Then 13
WHEN WEEKDAY(TODAY) = 4 Then 14
WHEN WEEKDAY(TODAY) = 5 Then 15
END #myvar1,
CASE
WHEN WEEKDAY(TODAY) = 1 Then 5
WHEN WEEKDAY(TODAY) = 2 Then 6
WHEN WEEKDAY(TODAY) = 3 Then 7
WHEN WEEKDAY(TODAY) = 4 Then 8
WHEN WEEKDAY(TODAY) = 5 Then 9
END #myvar2,
FROM q1
WHERE q1.etd BETWEEN today - #myvar1 AND today - #myvar2

I'm assuming that you're only using variables to try and reference the calculation in the SELECT clause from your WHERE clause. You can't reference aliases from the SELECT in your WHERE clause (at least not in most SQL systems). The reason is that The WHERE clause is evaluated before the select, so those aliases do not exist at the time the WHERE clause is being evaluated. You can use a subquery, however:
SELECT * FFROM
(SELECT
q1.host_po_nbr,
q1.etd,
CASE
WHEN WEEKDAY(TODAY) = 1 Then 11
WHEN WEEKDAY(TODAY) = 1 Then 12
WHEN WEEKDAY(TODAY) = 1 Then 13
WHEN WEEKDAY(TODAY) = 1 Then 14
WHEN WEEKDAY(TODAY) = 1 Then 15
END myvar1,
CASE
WHEN WEEKDAY(TODAY) = 1 Then 5
WHEN WEEKDAY(TODAY) = 1 Then 6
WHEN WEEKDAY(TODAY) = 1 Then 7
WHEN WEEKDAY(TODAY) = 1 Then 8
WHEN WEEKDAY(TODAY) = 1 Then 9
END myvar2,
FROM q1
) q
WHERE etd BETWEEN today - myvar1 AND today - myvar2

Try this:
SELECT
q1.host_po_nbr,
q1.etd,
CASE
WHEN WEEKDAY(TODAY) = 1 Then 11
WHEN WEEKDAY(TODAY) = 1 Then 12
WHEN WEEKDAY(TODAY) = 1 Then 13
WHEN WEEKDAY(TODAY) = 1 Then 14
WHEN WEEKDAY(TODAY) = 1 Then 15
END myvar1,
CASE
WHEN WEEKDAY(TODAY) = 1 Then 5
WHEN WEEKDAY(TODAY) = 1 Then 6
WHEN WEEKDAY(TODAY) = 1 Then 7
WHEN WEEKDAY(TODAY) = 1 Then 8
WHEN WEEKDAY(TODAY) = 1 Then 9
END myvar2,
FROM q1
HAVING q1.etd BETWEEN today - myvar1 AND today - myvar2
This, however, could be inefficient. If this does not solve your problem, post more details, in particular, your table structure (SHOW CREATE TABLE) and a good description of what you are trying to achieve.

Related

Pairwise swapping of rows in sql

I have a device settings table with threshold types and values.
Let's say ThresholdType = 0 is Min and ThresholdType = 1 is Max
The initial table looks like this:
DeviceID ThresholdType ThresholdValue
1 0 5
1 1 10
2 0 15
2 1 20
3 0 21
3 1 34
4 0 1
4 1 8
Then I had to change ThresholdType meaning - 0 became Max threshold and 1 became Min one.
I want the table look like that:
DeviceID ThresholdType ThresholdValue
1 0 10
1 1 5
2 0 20
2 1 15
3 0 34
3 1 21
4 0 8
4 1 1
Is it possible to change update it with a single SQL without loops?
Update ThresholdType instead:
update tablename set ThresholdType = 1 - ThresholdType
In case other ThresholdType values might show up later, you can add WHERE ThresholdType IN (1, 2), to be a bit safer.
Just swap the ThresholdType:
UPDATE t SET ThresholdType = CASE ThresholdType
WHEN 1 THEN 0
WHEN 0 THEN 1
ELSE ThresholdType
END
Execute the query exactly once.
You can do:
update t
set ThresholdValue = (
select x.ThresholdValue
from t x
where x.DeviceID = t.DeviceID and x.ThresholdType <> t.ThresholdType
)
Result:
DeviceID ThresholdType ThresholdValue
--------- -------------- --------------
1 0 10
1 1 5
2 0 20
2 1 15
See running example at db<>fiddle.

SQL / Impala , how to more quickly and efficient write increasing conditional statements?

I hope someone can help me here.
I'm writing a CASE in impala to find the missed lines in the table.
However, I need to write my example below to WHEN 1000 = 999. Instead of writing 1000 CASE lines, is there a more efficient and quicker solution that requires less code? It would help me a lot. Thank you.
CASE WHEN dif_tradecount = 2 THEN 1
WHEN dif_tradecount = 3 THEN 2
WHEN dif_tradecount = 4 THEN 3
WHEN dif_tradecount = 5 THEN 4
WHEN dif_tradecount = 6 THEN 5
WHEN dif_tradecount = 7 THEN 6
WHEN dif_tradecount = 8 THEN 7
WHEN dif_tradecount = 9 THEN 8
WHEN dif_tradecount = 10 THEN 9
WHEN dif_tradecount = 11 THEN 10
WHEN dif_tradecount = 12 THEN 11 .....
ELSE null
END AS missed_messages
if i got your task correct:
CASE
WHEN dif_tradecount > 1 and dif_tradecount<=1000 THEN dif_tradecount-1
ELSE null
END AS missed_messages
You could do:
(case when dif_tradecount between 2 and 1000
then dif_tradecount - 1
end) as missed_messages
I wonder why the case is necessary. Perhaps:
nullif(dif_tradecount - 1, 0) as missed_messages
would also work.

SQL Running total previous 3 months by date and id

This is a simplification of the table q3 I'm working with:
Partno EndOfMonth AA AS EA ES
a 31.5.2017 5 1 0 1
b 31.5.2017 3 1 0 1
c 31.5.2017 2 2 0 1
a 31.6.2017 1 2 2 2
b 31.6.2017 1 0 1 2
c 31.6.2017 2 3 1 4
a 31.7.2017 4 3 2 0
b 31.7.2017 3 0 6 0
c 31.7.2017 4 1 0 0
I need to sum the numbers in the last four columns for each part in Partno so that the sum represents the running total of the last three months at each date in the EndOfMonth column.
The result i'm looking for is:
Partno EndOfMonth AA AS EA ES
a 31.5.2017 5 1 0 1
b 31.5.2017 3 1 0 1
c 31.5.2017 2 2 0 1
a 31.6.2017 6 3 2 3
b 31.6.2017 6 1 1 3
c 31.6.2017 4 5 1 5
a 31.7.2017 10 6 4 3
b 31.7.2017 7 1 7 3
c 31.7.2017 8 6 1 5
So e.g. for partno A at 31.7.2017 the last thee months' sum for the 'AA' column is 4+1+5=10.
I'm quite new to SQL and am well and truly stuck with this. I've tried something like the following to just get a simple rolling total (without even specifying the sum range to be the last 3 months). Also, I'm not sure if the database even supports all the functions in the below code, since it's giving me the error "Incorrect Syntax near the keyword 'OVER'"
SELECT
Partno,
EndofMonth,
SUM(q3.AA) OVER (PARTITION BY q3.Partno ORDER BY EndofMonth ROWS UNBOUNDED PRECEDING) as 'AA'
FROM q3
Anyway, any help would be greatly appreciated!
Thanks
EDIT:
Thanks to Benjamin and with a little help from this post: https://dba.stackexchange.com/questions/114403/date-range-rolling-sum-using-window-functions
I was able to find the solution:
SELECT a.Partno, a.EndofMonth, SUM(b.AA) as 'AA', SUM(b.AS) as 'AS',...
FROM q3 a, q3 b
WHERE a.Partno = b.Partno AND a.endOfMonth >= b.endOfMonth
AND b.endOfMonth >= DATEADD(month,-2,a.endOfMonth)
GROUP BY a.Partno, a.endOfMonth
Something like this might work:
SELECT a.Partno, a.EndofMonth, SUM(b.AA) as AA
FROM q3 a, q3 b
WHERE a.Partno = b.Partno
AND DATEDIFF(month, b.endOfMonth, a.endOfMonth) < 4
GROUP BY a.Partno, b.Partno
This assumes that endOfMonth is in datetime format, if it is not you will have to use convert(). Note that you might have to replace DATEDIFF() depending on what implementation you are using.
I haven't tested this, so I might be way off. It has been a while since I worked with SQL. Hopefully you can get it working by messing around with it a bit, and if not then maybe it will inspire you to write something better. Let me know how it goes!

Use Multiple conditions in Case Statement

I have implemented multiple conditions in case statement as below,
select officied from budgettable
where budgetid = case #budgetid when 7 then 7
when 7 then 8
when 7 then 10
when 8 then 6
end
but it didn't give me any result. If I pass budget-Id as 7 the query should return 8,10,7 budget id's. Anything wrong in the above query?
I suspect that you want something like this:
where budgetid = #budgetid or
(#budgetid = 7 and budgetid in (7, 8, 10)) or
(#budgetid = 8 and budgetid = 6)
Your query is failing because for all values of #budgetid other than 7 or 8, the case returns NULL -- which is treated as false.
One option is to use the case as a boolean expression, returning 1 when your conditions are met:
select officied from budgettable
where 1 = case
when #budgetid = budgetid then 1
when #budgetid = 7 and budgetid in (7,8,10) then 1
when #budgetid = 8 and budgetid in (6,8) then 1
end
This expands the results returned by #budgetid 7 to include 8 and 10.
This is no answer. I just want to show how CASE WHEN works, so you see your mistake. Your query evaluates case #budgetidas follows:
when 7 then 7 => take a 7 for a #budgetid 7
when 7 then 8 => ignored, because we already said to take 7 for a #budgetid 7
when 7 then 10 => ignored, because we already said to take 7 for a #budgetid 7
when 8 then 6 => take a 6 for a #budgetid 8
end => no else here, so any other #budgetid results in NULL.
You then compare the result with = budgetid. This is never true for NULL. So you end up with:
where (#budgetid = 7 and budgetid = 7)
or (#budgetid = 8 and budgetid = 6)
This will work !!
SELECT
officied
FROM
budgettable
WHERE
1 = 1
AND
1 = CASE
WHEN
#budgetid = budgetid THEN 1
WHEN
(#budgetid = 7 AND budgetid IN (7,8,10)) THEN 1
WHEN
(#budgetid = 8 AND budgetid IN (6,8) THEN) 1
END
Better solution : Add a new column is_budget_calculated (Data type BIT) and update it as 0 and remaining as 1.

Simple Math iOS?

So in my app I am trying to do a simple math in one of my methods without using a ton of if/else statements.
So I have an integer named 'StartInt' which is at max 13. Now what I need to get is FinishInt an integer that will be the result of this pattern:
StartInt: 13 FinishInt: 1
StartInt: 12 FinishInt: 2
StartInt: 11 FinishInt: 3
etc... all the way down until StartInt is 1 and FinishInt is 13. Anyway how would I accomplish this? I know this must be simple but I am just not that great in Math! :)
All the way down until StartInt is 0 and FinishInt is 13. Anyway how
would I accomplish this?
That won't quite work if startInt = 13 gives finishInt = 1 and you want a finishInt to increment 1 for each decrement of startInt. Check out the following table:
13 1
12 2
11 3
10 4
9 5
8 6
7 7
6 8
5 9
4 10
3 11
2 12
1 13
So you're off by 1 at either the beginning or end of your sequence. Nevertheless, it looks like you want something like this:
(int) calculateFinish(int startInt)
{
int finishInt = -1;
if (startInt >= 0 && startInt <= 13) {
finishInt = 14 - startInt;
}
return finishInt;
}
That'd give a value of 14 for finishInt when startInt = 0.