Identify last record in CASE - sql

Probably an easy one... I have a SQL query along the lines...
SELECT a,
CASE WHEN a=1 THEN 'one'
WHEN a=2 THEN 'two'
ELSE 'other'
END
FROM test;
(from the docs)
I want to identify the last record in the set and act on that condition.

There are two possible scenarios from what you have explained in your question.
One of them is the one in which for the max value found in column a you want to display a certain message:
SELECT
a
, CASE
WHEN a = 1 THEN 'ONE'
WHEN a = 2 THEN 'TWO'
WHEN a = (SELECT MAX(a) FROM test) THEN 'MAX'
ELSE 'OTHER'
END
FROM TEST;
The other possible scenario is that only for the last record in the table you want to display that certain message. And in that scenario your query needs to change to:
SELECT
a
, CASE
WHEN a = 1 THEN 'ONE'
WHEN a = 2 THEN 'TWO'
WHEN a = (SELECT TOP 1 a FROM TEST ORDER BY a DESC) THEN 'MAX'
ELSE 'OTHER'
END
FROM TEST
ORDER BY A;

Related

Suggested sequence of responses in query

I have such values in the letter column:
A, B, C, D, E, **X**.
I would like the select to return to me such an order of
A, B, **X**, C, D, E.
I tried with ORDER BY, but I don't know if it's a good way, or it should be SELECT Top 2 and next...
If it's only one character:
order by case when MyColumn < 'C' then 1
when MyColumn = 'X' then 2
else 3
end,
MyColumn
In this case you should assign a numeric value to each of the possible values in order to get them in the desired way. It could be something like
order by case when column = 'A' then 1
when column = 'B' then 2
when column = 'C' then 3
when column = 'X' then 4
...
else 99999999
end
This can be done using a case expression to re-position the 'X' between 'B' and 'C' as follows.
order by case when MyColumn = 'X' then 'BB' else MyColumn end

Use of CASE with criteria from multiple tables

I have to do a select query to create a view with specific criteria.
I have multiple tables which contains many many columns and lines.
However, I have extracted a value to use as my key (e.g.: id). I have 7000+ of those unique keys that I extracted from all my tables with the function UNION to avoid duplicates.
Now, I want to add a column INDICATOR_1 which will affect the value YES or NO based on criteria.
This is where I struggle.
I need to find the line in those tables that contain the id. After that, I'd like to check, always in that line, if the field XYZ contains the value 'N' (example). If yes, affect the value 'YES' to INDICATOR_1, else it's no.
In a matter of pseudo-code, what I want to do looks like this :
CASE
WHEN id = (id from table_1) AND (if table_1.xyz = 'N')
THEN 'YES'
ELSE 'NO'
END AS INDICATOR_1
I don't know if I'm clear enough, but your help will be greatly appreciated.
If I understand correctly, you want a separate indicator for each table. Something like this:
select i.*,
(case when exists (select 1
from table1 t1
where t1.id = i.id and t1.xyz = 'N'
)
then 'YES' else 'NO'
end) as indicator_1,
(case when exists (select 1
from table2 t2
where t2.id = i.id and t2.xyz = 'N'
)
then 'YES' else 'NO'
end) as indicator_2,
. . .
from (<your id list here>) i
I think you should fix this in the union, where you have all the data you need. You probably have something like:
SELECT Id
FROM table_1
UNION
SELECT Id
FROM table_2
How about selecting the information you want as well (I use distinct here to clarify):
SELECT DISTINCT Id
, CASE WHEN table_1.xyz = 'N' THEN 'N'
ELSE 'Y'
END INDICATOR_1
FROM table_1
This can lead to more records than you had, if id's can have records of both flavours exist. We can fix that with a row number in an outer query. You end up with something like:
SELECT Id
, INDICATOR_1
FROM (
SELECT Id
, INDICATOR_1
, ROW_NUMBER()OVER(PARTITION BY ID ORDER BY CASE WHEN INDICATOR_1 ='N' THEN 0 ELSE 1 END) RN
FROM (
SELECT Id
, CASE WHEN table_1.xyz = 'N' THEN 'N'
ELSE 'Y'
END INDICATOR_1
FROM table_1
UNION
...
) T
) S
WHERE S.RN = 1
You can in fact shorten that by using the inner most case expression in the ROW_NUMBER expression.

How to create an alias that counts Ws, Ls, and Ds to create a record

I have a table with sports results with a column labeled 'Result' where the values in that column are either W, L, or D. I would like to create an alias column that will quickly count the Ws, Ls, and Ds from the whole table in that columns and display it as 'Count W-Count L-Count D'.
I'm very new to SQL and I haven't figured this specific of a request out, nor can I find the correct search terms in Google to discover a video or forum result for the situation I am looking for.
If you want the values in separate columns, use conditional aggregation:
select sum(case when result = 'W' then 1 else 0 end) as w_cnt,
sum(case when result = 'L' then 1 else 0 end) as l_cnt,
sum(case when result = 'T' then 1 else 0 end) as t_cnt
from t;
Best option go for group by
Select result, count(*) from table
where column IN ('W' , 'L' , 'D' )
group by result

How to summarize SQL table to return value conditionally

I have a table with several rows, and several columns. It looks like this:
Name Description
X PASS
X PASS
X FAIL
I want it to return only one row. If all of them are PASS, return PASS.
If one or more of them are FAIL, then return FAIL.
What's the best way to go about achieving this in SQL Server 2008?
EDIT: The values in the name column will always be the same.
Depending on the database indexes, and assuming you want one row returned per unique name, I would look at the performance of
select
name,
min([description]) as description
from
tableA
group by
name
compared to the other solutions
SELECT TOP 1 CASE Description WHEN 'FAIL' THEN 'FAIL' ELSE 'PASS' END
FROM DaTable
ORDER BY Description
OP: Is it possible that the table is empty? In that case this query won't return any rows, obviously.
EDIT
According to aquinas's comment I created a modified query without ordering:
SELECT CASE COUNT(Description) WHEN 0 THEN 'FAIL' ELSE 'PASS' END
FROM DaTable
WHERE Description = 'FAIL'
This query will return PASS if DaTable is empty.
This is the simplest solution you will find:
SELECT MIN(Description) FROM tbl
If there's at least one FAIL, then our result column will contain FAIL, otherwise, it will contain PASS.
You can use EXISTS to get the existance of a row containing "FAIL".
You could also try something like:
SELECT TOP 1 COALESCE(tFail.Description,t.Description)
FROM myTable AS t
LEFT JOIN myTable AS tFail ON tFail.Name = t.Name AND tFail.Description = 'FAIL'
WHERE t.Name = 'x'
Here is the query:
--DROP TABLE result
CREATE TABLE result(Name varchar(10),Description varchar(20))
--select * from result
INSERT INTO result
VALUES('X','PASS'),('X','PASS'),('X','FAIL')
;WITH CTE(descp,cnt) as (SELECT [description],COUNT(*) as cnt FROM result group by [description])
SELECT CASE WHEN COUNT(*) > 1 then 'FAIL' when COUNT(*)=1 then MAX(descp) else 'PASS' END FROM CTE

Returning custom values based on query results

Is it possible to make a query that returns a different custom value based on a query? Here is an example:
What I have in the table ...
number
1
2
3
... and this is what I want returned:
number
one
two
three
How can this be done?
You want a case statement. Depending on your flavor of SQL, something like this should work:
select
bar = case
when foo = 1 then 'one'
when foo = 2 then 'two'
else 'baz'
end
from myTable
Try
select value = case t.value
when 1 then 'one'
when 2 then 'two'
when 3 then 'three'
...
else null
end
from my_table t