ORDER BY CASE does not working? - sql

Hi I have SQL statement in DB2 which is working.
select distinct 'IN' as STATUS,
(select count(*) from table.......)
from table
UNION ALL
select distinct 'OUT',
(select count(*) from table.......)
from table
UNION ALL
select distinct 'FINISHED',
(select count(*) from table.......)
from table
order by status
But if I change the last line to
order by
case STATUS
when 'IN' then 1
when 'OUT' then 2
when 'FINISHED' then 3
end
My query does not work.
Can someone tell me how to solve this?
Thanks

Try wrapping the UNION into a derived table and order on that:
select *
from (
.... here goes your statement ...
) t
order by
case STATUS
when 'IN' then 1
when 'OUT' then 2
when 'FINISHED' then 3
end

you could always add the sort # to the status:
select distinct '1-IN' as STATUS,
(select count(*) from table.......)
from table
UNION ALL
select distinct '2-OUT',
(select count(*) from table.......)
from table
UNION ALL
select distinct '3-FINISHED',
(select count(*) from table.......)
from table
order by status

hello try this should work if i remember correctly
order by
case
when STATUS='IN' then 1
when STATUS='OUT' then 2
when STATUS='FINISHED' then 3
end
you could also name this when finishing
end as field_name

Related

How to use Dynamic Lag function to avoid joining a table to itself to retrieve date value

I'm currently writing code in SQL to add the column in red to the following table:
The logic is the following:
For every row:
if flag for this row =1 then use date of this row
if flag for this row =0 then find the latest row (based on date) on which flag was = 1 for the same party and return the date of that row. If no such row exists, return null
I've found a way to do this by joining the table to itself but I would like to avoid doing that as the size of the table is pretty massive.
What I have
select b.*, a.date,
from table a left join table b on a.party=b.party
where a.flag =1
Someone told me I could use the lag function, the partition over function and a case when to return the value I'm after but I haven't been able to figure it out.
Can someone help? Thank you so much!
try this
DECLARE #tab1 TABLE(PARTY CHAR(1),DATE DATE,Flag bit)
INSERT INTO #tab1
SELECT 'A','7-24-2018',1 Union ALL
SELECT 'A','7-28-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'B','7-13-2018',1 Union ALL
SELECT 'B','7-17-2018',0 Union ALL
SELECT 'B','7-18-2018',0 Union ALL
SELECT 'C','7-8-2018',1 Union ALL
SELECT 'C','7-13-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-20-2018',0
select t.*,
max(case when flag = 1 then date end) over (partition by PARTY order by date) as [Last Flag On Date]
from #tab1 t
try this :->
select b.*, a.date, from table a left join table b on a.party=b.party where a.flag = CASE WHEN a.flag = 1 THEN a.date WHEN a.flag = 0 THEN ( SELECT date FROM ( SELECT TOP 1 row_number() OVER ( ORDER BY a.date DESC ) rs , a.date FROM a WHERE a.flag = 1 GROUP BY a.date) s ) END
use CROSS APPLY() to obtain the latest row with flag 1
SELECT *
FROM yourtable t
CROSS APPLY
(
SELECT TOP 1 x.Date as [Last flag on date]
FROM yourtable x
WHERE x.Party = t.Party
AND x.Flag = 1
ORDER BY x.Date desc
) d
Yes it can be done by joining table, if written properly.
#Sahi query is also good and simple.
Since you were asking for Dynamic LAG()
This query may or may not be very performant,but it certainly worth learning.
Test this with various sample data and tell me for which scenario it do not work.
So that I correct my script accordingly.
DECLARE #tab1 TABLE(PARTY CHAR(1),DATE DATE,Flag bit)
INSERT INTO #tab1
SELECT 'A','7-24-2018',1 Union ALL
SELECT 'A','7-28-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'B','7-13-2018',1 Union ALL
SELECT 'B','7-17-2018',0 Union ALL
SELECT 'B','7-18-2018',0 Union ALL
SELECT 'C','7-8-2018',1 Union ALL
SELECT 'C','7-13-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-20-2018',0;
WITH cte
AS (SELECT *,
Row_number()
OVER (
partition BY party
ORDER BY flag DESC, [date] DESC ) rn
FROM #tab1)
SELECT *,
CASE
WHEN flag = 1 THEN [date]
ELSE Lag([date], (SELECT TOP 1 a.rn - a1.rn
FROM cte a1
WHERE a1.party = a.party))
OVER (
ORDER BY party )
END
FROM cte a

How can I filter an SQL table to show only keys with exactly N entries?

Lets say I have a table with a column named KEY.
I want to find all KEYs which are in the table exactly 3 times.
How can I do that?
I managed to get a list of how many entries I have for each KEY, like this:
select count(*) from my_table group by KEY;
but how can I filter it to show only those who have the value 3?
select KEY
from my_table
group by KEY
having count(*) = 3
The having clause filters after grouping (where filters before).
select `key`
from my_table
group by `KEY`
having count(*) = 3;
select KEY
from my_table
group by KEY
having count(1) = 3
Try with Row Number concept
;
WITH Temp_tab AS
( SELECT '1' Key_,'az' Key_Value
UNION SELECT '1' ,'a5'
UNION SELECT '1' ,'a6'
UNION SELECT '2' ,'a1'
UNION SELECT '3' ,'a2'
UNION SELECT '4' ,'a3'
UNION SELECT '1' ,'a4'
UNION SELECT '3' ,'a21'
UNION SELECT '3' ,'a22'),
Tab2 AS
(SELECT *, ROW_NUMBER() over(partition BY key_ ORDER BY key_) count_ FROM Temp_Tab)
SELECT key_
FROM tab2 WHERE count_ = 3
code for your table
;with temp_table
(select *,ROW_NUMBER() over(partition by key_ order by key_) count_ from my_table)
select key_ from temp_table where count_ = 3

multiple select in one query [Teradata]

I'm trying to do multiple select from diff tables and just have a result in one column.
SELECT COUNT(*) FROM tb1 union
SELECT COUNT(*) FROM tb2 union
SELECT COUNT(*) FROM tb3;
output should be like:
593643
18103600
0
Problem with this is that the result is being arranged on desc order.
Like below:
0
593643
18103600
I would want the result to be as I put the select statement.
Please advise. Btw, I'm using teradata.
Thank you.
SQL result sets are inherently unordered, unless you explicitly specify an order by clause. You can do this with a subquery:
select cnt
from ((SELECT COUNT(*) as cnt, 1 as ord FROM tb1)
union all
(SELECT COUNT(*), 2 FROM tb2)
union all
(SELECT COUNT(*), 3 FROM tb3)
) t
order by ord
If you want specific order, add ORDER BY clause. It would also be good to use UNION ALL so you always get 3 rows, even with duplicate results (two tables having the same number of rows):
SELECT 'tbl1' AS tablename, COUNT(*) AS cnt, 1 AS ord FROM tb1 UNION ALL
SELECT 'tbl2', COUNT(*), 2 FROM tb2 UNION ALL
SELECT 'tbl3', COUNT(*), 3 FROM tb3
ORDER BY ord ;

How to select case when more column for inserting?

i need your help to insert into from select but my query is too complex for me. My logic is below
INSERT INTO TheTable(A,CustomerNo,item,B,C,D)
SELECT DISTINCT
case when ((select count(*) from hesap where CustomerNo=e.CustomerNo)0) then
select top 1, A,CustomerNo,item+1,B,C,D
from dbo.Table1 order by ekno desc
) else select 100,e.CustomerNo,e.item,0,e.defterid,'C'
from Table2 e end
But i can not do that...
You can do case on column basis only.
What you can do is UNIONing two selects, and insert the result. Something like
INSERT INTO TheTable(A,CustomerNo,item,B,C,D)
SELECT ...
WHERE (select count(*) from hesap where CustomerNo=e.CustomerNo) = 0
UNION
SELECT select 100,e.CustomerNo,e.item,0,e.defterid,'C'
WHERE (select count(*) from hesap where CustomerNo=e.CustomerNo) > 0
I'm sorry, I cannot always follow your Select, but I hope you got the idea. You have to separate the 2 possibilities before you UNION them, so only 1 row can exist for each original row.
Can you try removing the comma after top 1 Like this:
INSERT INTO TheTable(A,CustomerNo,item,B,C,D)
SELECT DISTINCT
case when ((select count(*) from hesap where CustomerNo=e.CustomerNo)0) then
select top(1) A,CustomerNo,item+1,B,C,D
from dbo.Table1 order by ekno desc
)
else select 100,e.CustomerNo,e.item,0,e.defterid,'C'
from Table2 e end

Custom order after distinct statements

I want to make a custom order: IN, OUT, FINISHED.
If I left case statement I am getting in FINISHED, IN, OUT.
I found this solution but it does not work for me - I am getting error.
select distinct 'IN' as STATUS,
(select count(*) ...)
from table
UNION ALL
select distinct 'OUT',
(select count(*) ...)
from table
UNION ALL
select distinct 'FINISHED',
(select count(*) ...)
from table
order by
case STATUS
when 'IN' then 1
when 'OUT' then 2
when 'FINISHED' then 3
end
The query that you provided has some syntax irregularities. I think the following solves your problem:
select *
from ((select distinct 'IN' as statusA, (select count(*) ...
from table
)
union all
(select distinct 'OUT', (select count(*) ...)
from table
)
union all
(select distinct 'FINISHED', (select count(*) ...)
from table
)
) t
order by status,
(case STATUSA when 'IN' then 1
when 'OUT' then 2
when 'FINISHED' then 3
end)
Your original problem could have several causes. You were missing the 'IN' in the first subquery. You are missing the comma after status in the order by. And, some databases apply the final order by in a series of unions to only the last query (although I think DB2 does this correctly).