I have a SQL Select statement where I need to return certain values depending on a condition. I need to return multiple values each time, but my understanding of the Case statement is that you can only return a single value for each case.
I'm getting around this by using UNION statements at the moment, but it all looks a bit cumbersome - is there a better way to do this? Basically, I have a bunch of prompts, each with a response of either "Yes", "No" or "In Future" (I actually have more responses, but I'll just use 3 for the example to keep it short!) - I need to produce a column for each response type, with a 1 as the value for the appropriate response, and a 0 for all others. It's probably clearer to understand if you look at the SQL...
My (simplified) query looks like this:
SELECT branch,
promptType,
response,
1 AS 'Yes',
0 AS 'No',
0 AS 'Not Discussed'
FROM prompts
WHERE response = 'Y'
UNION
SELECT branch,
promptType,
response,
0 AS 'Yes',
1 AS 'No',
0 AS 'Not Discussed'
FROM prompts
WHERE response = 'N'
UNION
SELECT branch,
promptType,
response,
0 AS 'Yes',
0 AS 'No',
1 AS 'Not Discussed'
FROM prompts
WHERE response = 'D'
Something like...
SELECT branch,
prompttype,
CASE WHEN response = 'Y' THEN 'Yes'
WHEN response = 'N' THEN 'No'
WHEN response = 'D' THEN 'Not Discussed'
FROM prompts;
might be what you are after.
After your comment, perhaps...
SELECT branch,
prompttype,
CASE WHEN response = 'Y' THEN 1 ELSE 0 AS Yes,
CASE WHEN response = 'N' THEN 1 ELSE 0 AS No,
CASE WHEN response = 'D' THEN 1 ELSE 0 AS Not_Discussed
FROM prompts;
might do it.
Have you considered creating a decoding table for the responses, and joining to that?
For example, this would create a table for decoding the responses:
CREATE TABLE decoder (response CHAR(1), [Yes] BIT, [No] BIT, [Not Discussed] BIT)
INSERT INTO decoder VALUES ('Y', 1, 0, 0)
INSERT INTO decoder VALUES ('N', 0, 1, 0)
INSERT INTO decoder VALUES ('D', 0, 0, 1)
...and then you could join to it to get similar (the same?) results as you're getting with your UNION:
SELECT
prompts.branch,
prompts.prompttype,
prompts.response,
decoder.yes,
decoder.no,
decoder.[Not Discussed]
FROM
prompts INNER JOIN decoder ON prompts.response = decoder.response
Might be an approach worth considering; it's a more relational solution than your union, and probably easier to maintain.
You need to add grouping, I think. I did this with quarterly projections. If you have a unique ID for each response, it would be something like this (otherwise it will pick max for the whole branch/prompttype/response):
SELECT uniqueID,
branch,
prompttype,
response,
MAX(CASE WHEN response = 'Y' THEN 1 ELSE 0 END) AS Yes,
MAX(CASE WHEN response = 'N' THEN 1 ELSE 0 END) AS [No],
MAX(CASE WHEN response = 'D' THEN 1 ELSE 0 END) AS Not_Discussed
FROM prompts
GROUP BY uniqueID,
branch,
prompttype,
response;
SELECT branch,
prompttype,
response,
CASE WHEN response = 'Y' THEN 1 ELSE 0 END AS Yes,
CASE WHEN response = 'N' THEN 1 ELSE 0 END AS [No],
CASE WHEN response = 'D' THEN 1 ELSE 0 END AS Not_Discussed
FROM prompts;
If this proposed CASE statement of yours returned multiple values in a single column, what would the data type be: an array, a list, a table, an XML document, a business object, etc? For a truly relational database management system (TRDBMS), the answer would be a relation variable. But we are talking about SQL Server, here.
I think the answer you are looking for is that SQL Server's data types are scalar, not multivalued.
Related
I am trying to use simple IF query in sql developer (Oracle), but i get 'missing right parenthesis' Error. I want to write all ID from my table TEST_TABLE, and write yes if ID is 1234, else 'no'. What am i doing wrong?
select id, if(id = 1234, 'yes', 'no') from TEST_TABLE t
Can't use IF there (IF is for control flow in PLSQL code, not queries), use CASE WHEN instead:
select id, CASE WHEN id = 1234 THEN 'yes' ELSE 'no' END as idIs1234 from TEST_TABLE t
The basic form of a case when is:
CASE
WHEN test THEN truevalue
[WHEN othertest THEN othertruevalue]
[ELSE falsevalue ]
END
CASE must do one or more tests that each return a single value. If no case matches (all tests are false) and there is no ELSE clause, null is returned.
There is also a form that tests a single variable for equality against various values:
CASE id WHEN 1234 THEN 'yes1' WHEN 2345 THEN 'yes2' ELSE 'no' END
I want to return the sum of the values of one column when other column (in the same row speaking) is true. But, I can´t achieve...
I am trying the next ones, but no one looks to be correct.
Can I get a pinch of help here? Thanks mates.
ISNULL(SUM(CASE WHEN dbo.TD_MODULO.FIELD1== true THEN dbo.TD_MODULO.FIELD2 ELSE 0 end),0) AS MY_CALCULATED_FIELD1
isnull(sum(if dbo.td_modulo.FIELD1 == true, dbo.td_modulo.FIELD2, 0), 0) as MY_CALCULATED_FIELD2
ISNULL(SUM(CASE dbo.TD_MODULO.FIELD1 WHEN THEN dbo.TD_MODULO.FIELD2 ELSE 0 end),0) AS MY_CALCULATED_FIELD1
Is FIELD1 a bit (boolean) field ?, then compare it to 1 or 0
select sum(case when FIELD1 = 1 then FIELD2 else 0 end) AS MY_CALCULATED_FIELD1
from dbo.TD_MODULO
dbo.TD_MODULO.FIELD1 == true this raises an eyebrow. There is no boolean values in SQL Server so you can't simply write true or false (if a literal then 'true' or 'false', if a BIT then 1 or 0), and you need just one equal sign.
The correct expression is a SUM with a CASE. Assuming that TD_MODULO.FIELD1 is a VARCHAR.
SUM(CASE WHEN dbo.TD_MODULO.FIELD1 = 'true' THEN dbo.TD_MODULO.FIELD2 END)
You can stack an ISNULL on top of it. No need to do an ELSE 0, as NULL (ELSE's default) won't be added on SUM().
I am creating a store procedure and i am wondering how can i add a case block in an Add statement inside the where statement.That case statement checks an input parameter and depending its value it will change the condition from greater that to smaller than and of course be added to the add conditions
So a part of the query is like:
WHERE
AND BM.Example1 IS NOT NULL
AND BM.Example2 IS NOT NULL
AND ( Case When #inputParamter= 'A' THEN AND BM.Example < 0 ELSE And BM.Example> 0 )
ORDER BY 'SEG' ASC, 'CCY' ASC
So by this approach i am thinking to extract an add statement depending on the input parameter but unfortunately i keep getting syntax errors.
Is that possible?
Yepp, just use this:
AND (( #inputParamter= 'A' AND BM.Example < 0) OR ( #inputParamter<>'A' AND BM.Example> 0) )
However, be carefull with NULL, you have to put it in the logic as a third option.
here is a similar answer using case
AND ( Case When #inputParamter = 'A' AND BM.Example < 0 THEN 'Y'
When #inputParamter <> 'A' AND BM.Example > 0 THEN 'Y' ELSE 'N' END = 'Y')
I am trying to figure out how to turn multiple check box results in differnet fileds into seperate columns.
The current case statement below only tracked the lowest score into a a single filed called 'Activities Registered For (1) – (5)'. I would like to convert them into 5 columns 'a-e' where 'a' is always filled with a result, and if two options are checked the results are in 'a' and 'b'. The form can be filled in with up to all selections checked. The else statement appears to be an error, since there are to be at least one of the five boxes checked.
I am new to SQL and I adopted this from someone else, so I am sorry for not showing my previous attempts to resolve my issue.
,CASE
WHEN [1524#1] = 'Y' THEN '1'
WHEN [1525#1] = 'Y' THEN '2'
WHEN [1526#1] = 'Y' THEN '3'
WHEN [1527#1] = 'Y' THEN '4'
WHEN [1528#1] = 'Y' THEN '5'
ELSE ' ' END AS 'Activities Registered For (1) – (5)'
You could use a PIVOT but multiple CASEs are just as effective, use about the same amount of code and is easier for beginners to decipher.
CASE WHEN [1524#1] = 'Y' THEN 1 ELSE 0 END AS ACTIVITY_1,
CASE WHEN [1525#1] = 'Y' THEN 1 ELSE 0 END AS ACTIVITY_2,
CASE WHEN [1526#1] = 'Y' THEN 1 ELSE 0 END AS ACTIVITY_3,
CASE WHEN [1527#1] = 'Y' THEN 1 ELSE 0 END AS ACTIVITY_4,
CASE WHEN [1528#1] = 'Y' THEN 1 ELSE 0 END AS ACTIVITY_5
I don't think the ELSE is necessarily an error. I often add an ELSE than shouldn't be used in case there is unexpected data (no Y in any field in your example).
Here's some info on PIVOTs if you want to check it out:
http://www.codeproject.com/Tips/500811/Simple-Way-To-Use-Pivot-In-SQL-Query
In C, when you compared true/false value to 1/0, it worked very well.
I would want the similar possibility with SQL Server - when I have a bit column, I would like to compare myBitField = 'y' / myBitField = 'n'
Is there anything I can do about that? Maybe change some SQL interpreter settings or something?
Example of what I would like to do:
select * from
(
select CAST(1 AS BIT) as result
) as main
where main.result = 'y'
Currently, it throws an error, and I would like it to return 1/true/'y', whatever, but I would like it to be able to make that comparison.
I suppose you want to do it for some yes/no thing. But this is generally a wrong concept, your application which is accessing the SQL Server should interpret y as a 1 and n as a 0 and afterwards set the correct parameters for the query. You should not (actually I'm temped to write "must not") do this in SQL Server, that's what you have a business logic for.
As others have said, BIT and CHAR / VARCHAR are entirely different datatypes. But if you want to cast them during the select, you can use CASE expression like so:
-- Reading string as BIT
SELECT CAST(CASE RESULT WHEN 'Y' THEN 1 WHEN 'N' THEN 0 ELSE NULL END AS BIT) RESULT
-- Reading BIT as string
SELECT CAST(CASE RESULT WHEN 1 THEN 'Y' WHEN 0 THEN 'N' ELSE NULL END AS CHAR(1)) RESULT
And that's about as far as your options go here, far as I can understand. :)