Trouble with GROUP BY CASE - sql

The following query gives the error "#1241 - Operand should contain 1 column(s)" because of the (Department_Code, Course_Code) line. When I replace that with just (Course_Code) it works. However, that's not what I want
SELECT * FROM Classes
GROUP BY CASE
WHEN (1) THEN
Department_Code
ELSE CASE WHEN (2) THEN
(Department_Code, Course_Code)
ELSE Class_ID
END
END
How can I group by Department_Code, Course_Code when condition (2) is satisfied?

A case expression can only return a single value, so you need two case expressions. Also, use a single case expression for each instead of nesting two inside each other:
SELECT * FROM Classes
GROUP BY
CASE
WHEN (1) THEN
Department_Code
WHEN (2) THEN
Department_Code
ELSE
Class_ID
END,
CASE
WHEN (2) THEN
Course_Code
ELSE
1
END

Had the same problem but found a simpler way which was to construct a helper field that can then be referenced in the GROUP BY.
Or you can do the same conditional trick placing it in the GROUP BY so long as you Concat the fields.
SELECT *,
If( 'whatever field to check' = 2 , CONCAT(Department_Code,Course_Code), Course_Code) AS 'group1'
FROM Classes
GROUP BY group1

Related

Error in order clause of partition by when using multiple case statement

I want to use multiple case statement inside order by clause in partition by statement.
I have many columns so ,I am only posting the required one.
I have table customers which has:
Select
name,
ROW_NUMBER() OVER(PARTITON BY lastname, rollno
ORDER BY
CASE
WHEN
NVL(gender, address) IS NULL
then
a.effdate desc
else
CASE
WHEN
NVL(a.postoffc, a.mon) <= file.effdate
then
file.effdate
else
a.postoffc
END
desc, NVL(l4.covcode, a.pass)
end
)
rn
from
customers a;
If,i remove these case statement then my join with other tables and query is working fine.So,there is no problem in join statement or any other logic.The problem I get is when i used multiple case statement.I think my syntax is mistake.Please tell me how can solve this error.I need this case statement logic as mandatory.
You need to close the second CASE block before you declare the other ordering criteria. Also, you have an unwanted DESC within the expression, that should be placed after it.
ORDER BY
CASE
WHEN NVL(gender, address) IS NULL THEN a.effdate
ELSE CASE
WHEN NVL(a.postoffc, a.mon) <= file.effdate THEN file.effdate
ELSE a.postoffc
END
END desc, --> here
NVL(l4.covcode, a.pass)
But overall, I don't think that you need to nest the case expressions. This should work equally well, and is easier to follow:
ORDER BY
CASE
WHEN NVL(gender, address) IS NULL THEN a.effdate
WHEN NVL(a.postoffc, a.mon) <= file.effdate THEN file.effdate
ELSE a.postoffc
END desc,
NVL(l4.covcode, a.pass)

How to combine CASE statement with Inner Join for Alphanumeric OrderBY

In this query, I am trying to select all distinct (alphanumeric) machine names and order them correctly (1,2,5,10,15 instead of 1,10,15,2,5). The CASE statement is proven to work when the LocalName is not joined by INNER JOIN, so I suspect this is where the problem lies.
SELECT DISTINCT MCGroup, VisionMachinePerformance.MCSAP, ZAssetRegister.LocalName
FROM [VisionMachinePerformance] INNER JOIN ZAssetRegister ON VisionMachinePerformance.MCSAP=ZAssetRegister.SAP_Number
ORDER BY
CASE WHEN PATINDEX('%[0-9]%',LocalName) > 1 THEN
LEFT(LocalName,PATINDEX('%[0-9]%',LocalName)-1)
ELSE LocalName END ,
CASE WHEN PATINDEX('%[0-9]%',LocalName) > 1 THEN
CAST(SUBSTRING(LocalName,PATINDEX('%[0-9]%',LocalName),LEN(LocalName)) as float)
ELSE NULL END
The error that is reported is "SQL Error (145): ORDER BY items must appear in the select list if SELECT DISTINCT is specified".
I have tried changing all references in the CASE statement to ZAssetRegister.LocalName and VisionMachinePerformance.LocalName without success.
Removing all of the CASE statement and ordering by LocalName does work, but with the wrong order as mentioned above (1,10,15,2,5).
Could anybody suggest how to make this work?
TIA!
You can separate both parts using a subquery:
SELECT * FROM (
SELECT DISTINCT MCGroup, VisionMachinePerformance.MCSAP, ZAssetRegister.LocalName
FROM [VisionMachinePerformance]
INNER JOIN ZAssetRegister ON VisionMachinePerformance.MCSAP=ZAssetRegister.SAP_Number
) DISTINCT_DATA
ORDER BY
CASE WHEN PATINDEX('%[0-9]%',LocalName) > 1
THEN LEFT(LocalName,PATINDEX('%[0-9]%',LocalName)-1)
ELSE LocalName END,
CASE WHEN PATINDEX('%[0-9]%',LocalName) > 1
THEN CAST(SUBSTRING(LocalName,PATINDEX('%[0-9]%',LocalName),LEN(LocalName)) as float)
ELSE NULL END

SQL case statement: Return specified string if null else return select value

Below is an excerpt from my sql code, I am trying to return a string 'Off-Campus' if the value from select statement is null. If the value is not null, I want to return the value itself. However, I am getting an error:ORA-00904: "SITE_DESC": invalid identifier
00904. 00000 - "%s: invalid identifier"
Please advice on how I can go about this.
WHEN 'S' THEN (
case when(SELECT
site_desc
FROM
building
WHERE
site_code = (
SELECT
code
FROM
table2
WHERE
name = 'code'
)
) is null then 'Off-Campus' else site_desc end
)
WHEN 'F' THEN (
.... ...... .......
)
Try COALESCE:
WHEN 'S'
THEN
COALESCE(SELECT
site_desc
FROM
building
WHERE
site_code = (
SELECT
code
FROM
table2
WHERE
name = 'code'
),'Off-Campus')
You can use COALESCE:
WHEN 'S' THEN (
COALESCE(SELECT site_desc
FROM building
WHERE site_code IN (SELECT code
FROM table2
WHERE name = 'code'),
'Off-Campus')
Or:
WHEN 'S' THEN (
COALESCE(SELECT site_desc
FROM building
WHERE site_code = (SELECT TOP 1 code
FROM table2
WHERE name = 'code'),
'Off-Campus')
The difference between these two is how you handle the innermost subquery, since it's in your where clause you can either test that your value site_code is IN the results, or guarantee one result by only taking the TOP 1 and testing for equality. Doing either is good practice even if you can guarantee only one name = 'code' in table2. The first option is likely to be more useful, as it will return all codes for name='code' and test if site_code is in the results.
COALESCE(expression [,... expressionN]) goes through the expressions passed in from left to right, evaluating each until it has none left to evaluate or finds one that returns a value other than null. You can pass any number of arguments to it and it will return the first one that is not null. In your case the second expression is a hard coded string and the first is a subselect which may return null.
You could write this using coalesce():
WHEN 'S'
THEN coalesce( (SELECT site_desc
FROM building
WHERE site_code = (SELECT code FROM table2 WHERE name = 'code')
), 'Off-Campus'
)
I can't say I'm a fan of the nested subquery, so there might be a simpler way to express the logic.

How to nest a CTE (Common Table Expression)

I have the below query
With max_cm1 as (select * from tableA)
Select * ,
CASE WHEN TO_CHAR(CCP2.END_DATE,'MM/DD/YYYY') <> '09/09/9000' THEN 'CLOSED'
WHEN MAX_CM1.MAX_ROLE_CM IS NOT NULL AND HIST.PCMUID IS NOT NULL THEN 'ASSIGNED'
ELSE 'UNASSIGNED'
END STATUS
from max_cm1
Now I need to filter on the case statement. How can I do this?
You can use an alias eg: m.
With max_cm1 as (select * from tableA)
Select m.* ,
CASE WHEN TO_CHAR(CCP2.END_DATE,'MM/DD/YYYY') <> '09/09/9000' THEN 'CLOSED'
WHEN MAX_CM1.MAX_ROLE_CM IS NOT NULL AND HIST.PCMUID IS NOT NULL THEN 'ASSIGNED'
ELSE 'UNASSIGNED'
END STATUS
from max_cm1 m;
In your case, you don't need a CTE unless you are joining it with other table with some expressions in CTE. Directly you can fetch from table A with the same method if you are only interested in select '*'.
Your question is unclear. Also, the query as given is somewhat confusing, as it qualifies some columns with table names (CCP2 and HIST) that don't appear elsewhere in the query. Further, as written there seems to be no purpose to the CTE at all.
I'm assuming that what you want is to include the given CASE expression in the result set, but also use it within the WHERE clause to filter the results (e.g. WHERE CASE ... END = 'CLOSED'. The simple way to do this is to repeat the CASE expression; but of course duplicating logic is never a good choice. So the better way, which I think is the point of your question, is to include that derived column in a CTE so you can then refer to it by name in the WHERE clause.
It also looks like you are probably running into the issue of trying to select all columns (*) plus a derived column. The way around this is to qualify the * with the table name, or an alias as indicated in one of the other answers.
Putting this all together, I believe you want something like the following. I'm keeping the column expressions (e.g. HIST.PCMUID) as you wrote them although as written they make no sense. I'm guessing that tableA really represents some join of multiple tables.
WITH max_cm1 AS (
SELECT tableA.* ,
CASE WHEN TO_CHAR(CCP2.END_DATE,'MM/DD/YYYY') <> '09/09/9000' THEN 'CLOSED'
WHEN MAX_CM1.MAX_ROLE_CM IS NOT NULL AND HIST.PCMUID IS NOT NULL THEN
'ASSIGNED'
ELSE 'UNASSIGNED'
END STATUS
FROM tableA
)
SELECT *
FROM max_cm1
WHERE status = 'CLOSED'

How Do I Use Case Statement Column In Group By

As stated by the question, I'm trying to formulate a query that has a case statement in the column results, and then I want to include that column in the query's group by statement. To give a concrete example, here is all little of what my query looks like:
SELECT SOME_TABLE_ALIAS.COLUMN1, OTHER_TABLE_ALIAS.COLUMN2,
CASE
WHEN SOME_TABLE_ALIAS.COLUMN3 IS NOT NULL THEN 'A'
ELSE 'B'
END AS CASE_COLUMN
FROM SOME_TABLE SOME_TABLE_ALIAS
... (other table joins and where clauses)
GROUP BY SOME_TABLE_ALIAS.COLUMN1, OTHER_TABLE_ALIAS.COLUMN2, CASE_COLUMN
Before coming here, I checked out a few websites, including this one, to try solve my problem. I've tried adding another alias after the CASE keyword like is shown in the linked web page but have had no luck. The error message I continue to receive is the following:
[Error] Script lines: 127-151 ----------------------
CASE_COLUMN IS NOT VALID IN THE CONTEXT WHERE IT IS USED. SQLCODE=-206, SQLSTATE=42703, DRIVER=3.53.71
Has anyone else run into the issues I'm facing and been able to use a GROUP BY on the results of a CASE statement? Any help would be appreciated. Oh, and the DB2 version is a z/OS instance, version 10 (DSN10015)
The alias isn't available to use in the GROUP BY because when GROUP BY happens the alias isn't defined yet:
Here's the order:
1.FROM
2.WHERE
3.GROUP BY
4.HAVING
5.SELECT
6.ORDER BY
You can work around that with:
SELECT column1,column2,case_column
FROM (
SELECT SOME_TABLE_ALIAS.COLUMN1, OTHER_TABLE_ALIAS.COLUMN2,
CASE
WHEN SOME_TABLE_ALIAS.COLUMN3 IS NOT NULL THEN 'A'
ELSE 'B'
END AS CASE_COLUMN
FROM SOME_TABLE SOME_TABLE_ALIAS
... (other table joins and where clauses)
) a
GROUP BY COLUMN1, COLUMN2, CASE_COLUMN
Or just use the case you use in SELECT in GROUP BY
You can either use the case as is in the group by, like this:
SELECT SOME_TABLE_ALIAS.COLUMN1, OTHER_TABLE_ALIAS.COLUMN2,
CASE
WHEN SOME_TABLE_ALIAS.COLUMN3 IS NOT NULL THEN 'A'
ELSE 'B'
END AS CASE_COLUMN
FROM SOME_TABLE SOME_TABLE_ALIAS
... (other table joins and where clauses)
GROUP BY SOME_TABLE_ALIAS.COLUMN1, OTHER_TABLE_ALIAS.COLUMN2,
CASE
WHEN SOME_TABLE_ALIAS.COLUMN3 IS NOT NULL THEN 'A'
ELSE 'B'
END
or use a sub-query like this:
select COLUMN1, COLUMN2, CASE_COLUMN
from (
SELECT SOME_TABLE_ALIAS.COLUMN1, OTHER_TABLE_ALIAS.COLUMN2,
CASE
WHEN SOME_TABLE_ALIAS.COLUMN3 IS NOT NULL THEN 'A'
ELSE 'B'
END AS CASE_COLUMN
FROM SOME_TABLE SOME_TABLE_ALIAS
... (other table joins and where clauses)
) a
GROUP BY COLUMN1, COLUMN2, CASE_COLUMN