sql query with a case when returning more than one row - sql

I'm trying to do a query with a case when condition to see what list I will show but I'm having this error ORA-01427: single-row subquery returns more than one row.
the query is this:
SELECT
CASE WHEN action_type like 'Trigger Severity' THEN (select cast(SEVERITY as varchar2(255)) name from SURV_TRIGGER_SEVERITY_LIST)
WHEN action_type like 'Host Group' then (select cast(name as varchar2(255)) name from Surv_List.groups)
WHEN action_type like 'Host' then (select cast(name as varchar2(255)) name from tn_tree)
END display_value
FROM surv_action_type_list
WHERE id = 0
is it possible to call a query with more than one row inside a case condition?

I would do this in multiple steps. Get the action type, then issue the appropriate query. Whether you have this logic at the front end or in a stored procedure is up you and probably depends on a lot of other things.
If you absolutely needed to do it this way, then you could try something like this:
SELECT
SQ.display_value
FROM
surv_action_type_list SATL
INNER JOIN
(
SELECT
'Trigger Severity' action_type,
CAST(severity AS VARCHAR2(255)) display_value
FROM
SURV_TRIGGER_SEVERITY_LIST
UNION ALL
SELECT
'Host Group' action_type,
CAST(name AS VARCHAR2(255) display_value
FROM
Surv_List.groups
UNION ALL
SELECT
'Host' action_type,
CAST(name AS VARCHAR2(255) display_value
FROM
tn_tree
) SQ ON
SQ.action_type = SATL.action_type
WHERE
SATL.id = 0

You have 3 sub-queries.
1. select cast(SEVERITY as varchar2(255)) name from SURV_TRIGGER_SEVERITY_LIST
2. select cast(name as varchar2(255)) name from Surv_List.groups
3. select cast(name as varchar2(255)) name from tn_tree
Each one must return 0 or 1 rows but not more.

No. Your subquery should return only one value (only one row and one column) since you'll display it on a single row.
Since you are displaying the value as one column using your query above, it looks like your intention is to get only one value.
select
CASE WHEN action_type like 'Trigger Severity' THEN (select cast(SEVERITY as varchar2(255)) name from SURV_TRIGGER_SEVERITY_LIST)
WHEN action_type like 'Host Group' then (select cast(name as varchar2(255)) name from Surv_List.groups)
WHEN action_type like 'Host' then (select cast(name as varchar2(255)) name from tn_tree)
END display_value
from surv_action_type_list
where id = 0
Is there a where missing that links this ID to say a Severity list?
Usually queries like this would have a condition in the subquery.. something like..
select
CASE WHEN action_type like 'Trigger Severity'
THEN (select cast(SEVERITY as varchar2(255)) name
**from SURV_TRIGGER_SEVERITY_LIST trglst
where trglst.name = lst.severity_name**
-----
---
END display_value
from surv_action_type_list lst
where id = 0

Related

How to combine multiple records in one in SQL

I have a SQL table that looks something like this:
OP
ID
First name
Last name
Phone number
I
123
John
Smith
888-555
U
123
777-555
I have to combine this rows through select query into something like this:
ID
First name
Last name
Phone number
123
John
Smith
777-555
I have trouble writing query because my only idea is with MAX, but sometimes is field from U row lesser than the one in I row and I need to check every column.
What I tried:
Select ID,
max('First name') as 'First name',
max('Last name') as 'Last name',
max('Phone number') as 'Phone number'
from table
group by ID
Please help.
You seem to want a priority, with U first then I. One method is to use coalesce() with conditional aggregation:
select id,
coalesce(max(case when OP = 'I' then first_name end),
max(first_name)
) as first_name,
coalesce(max(case when OP = 'I' then last_name end),
max(last_name)
) as last_name,
coalesce(max(case when OP = 'I' then phone_number end),
max(phone_number)
) as phone_number
from t
group by id;
You could use the JOIN keyword to join the two tables together with the max values included.
Here's a link to reference the code you're looking for: Select only rows by join tables max value
You can use an autoreferenced JOIN to search the not null rows and OP = I, to not depends of a MAX
SELECT a.OP, a.ID,
COALESCE(a.'First name',b.'First name'),
COALESCE(a.'Last name',b.'Last name'),
'Phone number'
FROM table a
LEFT JOIN (SELECT * FROM table WHERE OP = 'I' AND and 'First name' IS NOT NULL AND 'Last name' IS NOT NULL LIMIT 1) b ON b.ID = a.ID;

SQL if column is empty, add an empty column

I want to be able to check if we have a column and if not, then we just want to add an empty column,
IF Users.[parties] = '' OR NULL
BEGIN
SELECT [parties]
FROM Users
UNION
SELECT 'Empty'
END
The Users.[parties], we check to see if we have a column but if we don't, it will result in a crash, in the case for this event I thought it would be best just to add an empty column with the name of Empty but I can't get the code to work above.
If we do have columns, the results will be something like...
ColumnsName ColumnAge
data 33
data 22
But when there isn't a column, it crashes and ideally I would like it to just have an empty column like this,
EmptyColumn
The code below checks whether a column exists in the table, in our case the name of the column is columnName and the name of the table is tableName.
IF COL_LENGTH('schemaName.tableName', 'columnName') IS NOT NULL
BEGIN
-- Column exists
SELECT [parties] FROM Users
END
ELSE
BEGIN
-- Column does not exists
SELECT 'Empty'[parties]
END
I think you just want
IF EXISTS(
SELECT 1
FROM Sys.Columns
WHERE Name = N'parties'
AND
Object_ID = Object_ID(N'SchemaName.Users')
)
BEGIN
SELECT parties
FROM Users;
END
ELSE
BEGIN
SELECT 'EmptyColumn' EmptyColumn -- or NULL EmptyColumn
FROM Users;
END
I'll try with this: (I'm not sure it works)
select case when ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) =0 --count rows
then 'empty' -- if 0 output empty
else parties end as parties --else ouputs the result
from your_table
This is a more 'standard' approach
CREATE VIEW user_filled as
SELECT [parties]
FROM Users
UNION
SELECT 'EMPTY'
and when you query it (if needed -> on count(*))
select count(*)
from user_filled
where parties <> 'EMPTY'
on join
select *
from user_filled join other_table
on (user_filled <> 'EMPTY and userfilled.key= other_table.key)
NOTE: put the clause into the ON so it's filtered out BEFORE the join is made

Use generated column to create another column - SQL Server

I have a column that gets generated using CAST(CASE WHEN A and B THEN SSS) as Name
Now I need another column which will use the value of the column above in the same way (CASE WHEN Name SSS THEN 123)
Is that possible?
UPDATE:
Example:
I have a table with
Name, Age, UserCode, UserId
I would like to generate a table using SELECT which includes
Name, UserCode, UserName
Name: returned from the column Name
UserCode:
CAST(CASE WHEN UserCode = 'A' and UserId = 'B' THEN 'SSS'
CASE WHEN UserCode = 'C' and UserId = 'Z' THEN 'ZAZ')
UserName: use the result from UserCode, so if UserCode is SSS then UserName become SAR123 etc...
Try this:
Select *,
CASE UserCode
When 'SSS' Then 'SAR123'
--When ... --<<Put other When clauses here
END AS UserName
FROM(
Select Name ,
CASE WHEN UserCode = 'A' and UserId = 'B' THEN 'SSS'
WHEN UserCode = 'C' and UserId = 'Z' THEN 'ZAZ'
END AS UserCode
From Table
) AS K
The alias of column name are obtained after the FROM, WHERE and then SELECT clause code evaluation .. so these alias are not available before this evalution is finished for this reason
alias of column name are not allowed in select or where clause and for these clause you must rewrite the code when need
select (CASE WHEN CAST(CASE WHEN A and B THEN SSS .....) SSS THEN 123 .... )
FROM my_table
.......
but alias for column name are available for ORDER BY and GROUP BY (clause that are evalueted after the previous mentioned)
alias of coulmn can be used in order by and group by

How to retrieve list from SQL alphabetically except one item?

I have a table with a column for Occupations in a table in SQL. Along with a few occupations, I also have an item for 'others'. I will display these in a dropdownlist and on selecting 'others' I will show a text box.
Ex: Business
Student
Employee
Others
I want to retrieve the list in Ascending Order, but when I do that using ORDER BY ASC 'Others' will come somewhere in between. I want it to be at the end of the list being returned.
Like Business
Employee
Student
Other
Please suggest a solution to keep the Others at the end of list while retrieving.
(Note: The list is dynamic and will be changing , so I cannot hardcode)
Try something like
SELECT * FROM
(
SELECT *,
CASE WHEN <YourValue> = 'Others' THEN 1 ELSE 0 END AS PrimaryOrder
FROM <YourTable>
) AS SubQuery01
ORDER BY PrimaryOrder, YourOrderByCriteria
A possible solution:
select occupations from mytable where occupations != 'Others' order by 1 ASC
union
select occupations from mytable where occupations == 'Others';
but it's overkill, you can add others by hand
I have tried out a solution and is working for me..
SELECT O.NAME FROM OCCUPATIONTABLE O
ORDER BY CASE
WHEN O.NAME = 'Others'
THEN 1
ELSE 0
END ASC
,O.NAME ASC

Select an ID if count is equal to 1

I am trying to write a query which needs to find an ID number from 3 WHERE values based on the result only being equal to 1.
So say i want to find a patient's ID and my where clause matches the firstname, lastname and DOB. If there are 2 results because of duplicates, i need the output to be NIL else it should return the patient ID.
if(select count(*)
from patient
where last_name = 'JAMES'
and first_name = 'JONES'
and birth_DtTM = '1980-01-01') > 1
print 'NULL' else return Pat_ID1
This is kind of what i am leading towards.
Thanks guys
select case when count(*)> 1
then 'NULL' else Pat_ID1 end
from patient
where last_name = 'JAMES'
and first_name = 'JONES'
and birth_DtTM = '1980-01-01'
group by Pat_ID1
try below.
;WITH CTE(Pat_ID1,last_name,first_name,birth_DtTM,dup_rows)
as
(
SELECT Pat_ID1,last_name,first_name,birth_DtTM,ROW_NUMBER() OVER(PARTITION BY last_name,first_name,birth_DtTM ORDER BY Pat_ID1) AS dup_rows FROM patient
)
SELECT
case when dup_rows>1 then null
when dup_rows=1 then Pat_ID1
end
FROM CTE
You can do it like this:
SELECT
PatientID = CASE COUNT(*) WHEN 1 THEN MAX(Pat_ID1) END
FROM
patient
WHERE
last_name = 'JAMES'
AND first_name = 'JONES'
AND birth_DtTM = '1980-01-01'
;
The CASE expression will evaluate either to the single Pat_ID1 matching the request or to NULL (if COUNT(*) is anything but 1).
As you can see, the Pat_ID1 value is obtained with the help of an aggregate function (by the way, you can use MIN instead of MAX just as well). This is because the presence of COUNT(*) in the query automatically implies grouping and now, if you want to reference columns of the underlying row set, you must only access their aggregated values.