Getiing multiple rows as output using case statement in sql - sql

I have a table,
id category column1 column2 column3
1 1 val1a val1b val1c
2 2 val2a val2b val2c
3 3 val3a val3b val3c
from which I need to select columns based on multiple conditions something like below.
SELECT id, category, column1, column2, column3
FROM table
WHERE id = #id
AND category IN (
select case when (#input1='Yes' AND #input2='Yes') then (select category from table where category in ('1','2'))
when (#input1='Yes' AND #input2='No') then (select category from table where category ='1')
when (#input1='No' AND #input2='Yes') then (select category from table where category ='2')
else ''
end as category)
END
Input values #input1 and #input2 are grabbed from another table, need to select and output rows with category in ('1','2') according to above condition.
What I need -
if input1=Yes and input2=Yes output rows with category in ('1','2')
if input1=Yes and input2=No output rows with category in ('1')
if input1=No and input2=Yes output rows with category in ('2')
if input1=No and input2=No output rows with category in ('')
Does case statement output multiple values? Need help.

check out the code below, you don't need to use CASE WHEN, just use where condition combinations will do the trick.
create table [Test] ( id int, category nvarchar(10));
insert [Test] values(1,'1');
insert [Test] values(2,'2');
insert [Test] values(3,'1');
insert [Test] values(4,'2');
declare #input1 varchar(10) = 'Yes'
declare #input2 varchar(10) = 'No'
SELECT id, category
FROM [Test]
WHERE
(
( #input1 = 'Yes' and category ='1')
or
( #input2 = 'Yes' and category ='2')
)

If you wanted to use in, you could use:
where id = #id and
category in ( (case when #input1 = 'Yes' then 1 end),
(case when #input2 = 'Yes' then 2 end)
)
The default value for the case is NULL and that will fail any comparison.
Also, note that I removed the single quotes around '1' and '2'. These look like numbers, so I assume that category is a number. Quotes should only be used around string and date constants.

Maybe this:
SELECT id, category, column1, column2, column3
FROM table
WHERE id = #id
AND category IN
(
select category
from table
where
(
category = '1'
AND
#input1='Yes'
)
OR
(
category = '2'
AND
#input1='Yes'
)
)
or this:
SELECT id, category, column1, column2, column3
FROM table
WHERE id = #id
AND
(
(
#input1='Yes' AND #input2='Yes' AND category IN (select category from table where category in ('1','2')
)
OR
(
#input1='Yes' AND #input2='No' AND category IN (select category from table where category ='1')
)
OR
(
#input1='No' AND #input2='Yes' AND category IN (select category from table where category ='2')
)
)

I would suggest you to form a mapping table and leverage it in the SELECT query. It will result in simplified code and more clear approach.
;WITH CTE_MappingTable AS
(
SELECT *
FROM
(
values
('Yes','Yes',1),
('Yes','Yes',2),
('Yes','No',1),
('No','Yes',2)
) as t(input1,input2,category)
)
SELECT id, category, column1, column2, column3
FROM table as t
INNER JOIN CTE_MappingTable as c
ON c.Category = t.Category
WHERE id = #id AND c.input1 = #input1 AND c.input2 = #input2

Related

Need to return an ID which has start and END in sql server

I have a scenario wherein I need to find the ID which only has start and END in it. Below is the table for reference.
Declare #T Table ( ID int, Name varchar(100))
Insert into #T values (1,'Start')
Insert into #T values (1,'END')
Insert into #T values (1,'Stuart')
Insert into #T values (1,'robin')
Insert into #T values (2,'Start')
Insert into #T values (2,'END')
Insert into #T values (3,'Start')
Insert into #T values (4,'END')
I want the Output as:
ID Name
2 Start
2 END
I want those ID which only has start and end in it.
What I tried so far:
SELECT * FROM #T t
WHERE EXISTS (SELECT * FROM #T WHERE id = t.id AND name = 'start')
AND EXISTS (SELECT * FROM #T WHERE id = t.id AND name = 'END')
But my query is giving ID 1 as well.
Can someone please help me rectify the problem.
I presume your issue is that record 1 has a 'Stuart' in it too?
As such, you can do a similar check in the WHERE e.g.,
SELECT * FROM #T t
WHERE EXISTS (SELECT * FROM #T WHERE id = t.id AND name = 'start')
AND EXISTS (SELECT * FROM #T WHERE id = t.id AND name = 'END')
AND NOT EXISTS (SELECT * FROM #T WHERE id = t.id AND name NOT IN ('start','END'))
Note that you may want to consider
What happens if you have two 'start' rows or two 'end' rows (e.g., start-start-end)? Can you even have two 'start' rows (e.g., start-start)?
What happens if you have a blank/NULL (e.g., start-NULL-end)?
EDIT: removed 'What happens if they're out of order (e.g., end-start)?' as a question as there is no sorting in the data at all (e.g., not even an implicit sort).
You can go for CTE to get group wise count and total count as 2.
Declare #T Table ( ID int, Name varchar(100))
Insert into #T values (1,'Start')
Insert into #T values (1,'END')
Insert into #T values (1,'Stuart')
Insert into #T values (1,'robin')
Insert into #T values (2,'Start')
Insert into #T values (2,'END')
Insert into #T values (3,'Start')
Insert into #T values (4,'END')
;WITH CTE_Total_StartEnd AS
(
select id, count(*) AS Total_Cnt
, COUNT( case when Name IN ('Start') THEN 1 END) as start_cnt
, COUNT( case when Name IN ('End') THEN 1 END) as end_cnt
from #t
group by id
having COUNT( case when Name IN ('Start') THEN 1 END) =1 and
COUNT( case when Name IN ('End') THEN 1 END) = 1 and
count(*) = 2
)
SELECT t.* from #t t
inner join CTE_Total_StartEnd as c
ON c.id = t.id
+----+-------+
| ID | Name |
+----+-------+
| 2 | Start |
| 2 | END |
+----+-------+
You can do this by using group by function also like below
WITH cte AS
(
SELECT 1 AS id , 'Start' AS name
UNION ALL
SELECT 1 AS id ,'END' AS name
UNION ALL
SELECT 1 AS id ,'Stuart' AS name
UNION ALL
SELECT 1 AS id ,'robin' AS name
UNION ALL
SELECT 2 AS id ,'Start' AS name
UNION ALL
SELECT 2 AS id ,'END' AS name
UNION ALL
SELECT 3 AS id ,'Start' AS name
UNION ALL
SELECT 4 AS id ,'END' AS name
)
SELECT T.ID,SUM(T.VAL)AS SUM
FROM
(
SELECT id,name , CASE WHEN name='Start' THEN 1
WHEN name='END' THEN 2
ELSE 3
END AS VAL
FROM cte
)T
GROUP BY T.ID
HAVING SUM(T.VAL) =3
could you please try this? Pls note i added collate command in the end of sql.
SQL Server check case-sensitivity?
SELECT * FROM #T t
WHERE EXISTS (SELECT * FROM #T WHERE id = t.id AND name = 'start' COLLATE SQL_Latin1_General_CP1_CS_AS)
AND EXISTS (SELECT * FROM #T WHERE id = t.id AND name = 'END' COLLATE SQL_Latin1_General_CP1_CS_AS)

SQL Return default values if no rows returned

I've got a SQL script which returns a result set, the requirement is to return a default result set with default values if the below script does not yield any results. It should have the same column names as the below script
-- Return final results
SELECT
p.worked [AccountsWorked],
p.rcmade [RPC's],
p.obtained [PTPCount],
p.amount [PTPValue],
[PreviousDayPTPValue]
FROM
#tab_performance p JOIN
dbo.user usr ON
(p.usr_code = usr.usr_code) JOIN
dbo.team tme ON
(tme.tme_id = usr.tme_id)
AND p.usr_code = #usr_code
I need to return a default result set if no rows are returned. So all the columns should be returned with NULL's or any default value.
I have tried conditional select statements without any luck, I have also tried the ##ROWCOUNT
You can add a union all select to your existing query with default values like this:
<your existing query>
union all
select null accounts_worked, null right_contacts_made, null ppts_obtained .....
where not exists(
select *
from #tab_performance p JOIN
dbo.TR_USR_User usr ON
(p.usr_code = usr.usr_code) JOIN
dbo.TR_TME_Team tme ON
(tme.tme_id = usr.tme_id)
AND p.usr_code = #usr_code
)
The where clause could be further simplified, if your inner joins don't filter out any rows from #tab_performance:
<your existing query>
union all
select null accounts_worked, null right_contacts_made, null ppts_obtained .....
where not exists(
select *
from #tab_performance
where usr_code = #usr_code
)
I would do it with WITH and UNION ALL
Drop table if exists #test
create table #test (
Column1 int null,
Column2 varchar(50) null
);
--INSERT INTO [#test] (Column1,Column2)
--VALUES
-- (1, 'test'),
-- (2,'test2'),
-- (3,'test3');
WITH qry AS (
select Column1, Column2 from #test
)
select * from qry
UNION ALL
select NULL as Colum1, null as Column2 where (select COUNT(*) from qry) = 0

i want the help in CTE to display header name from the table value

I am trying to fetch few records from the table. I have one category mapped to multiple subcategory. I want header name as subcategory description of each record.
I have done below and splitted category with row number.
DROP TABLE #temp
CREATE TABLE #temp ( [Description] VARCHAR(100), SubDescription VARCHAR(100), IsOMExceptionRequired bit,IsAMB bit,IsARS bit,escalationtypeid int, CategorySortOrder int, SubcategorySortorder int);
INSERT INTO #temp ([Description], SubDescription, IsOMExceptionRequired ,IsAMB,IsARS,escalationtypeid,CategorySortOrder,SubcategorySortorder)
SELECT C.Description,s.Description, S.IsOMExceptionRequired,s.IsAMB,s.IsARS,CEM.escalationtypeid, c.SortOrder,s.SortOrder
FROM category C
INNER JOIN SubCategory S on C.CategoryID =S.CategoryID
INNER JOIN CategoryEscalationTypeMap CEM on CEM.CategoryID= C.CategoryID
WHERE CEM.escalationtypeid=3 and CEM.IsActive =1 and C.IsActive=1 and S.IsActive=1
order by CEM.escalationtypeid, C.sortorder,S.sortorder;
--select * from #temp;
WITH Temp
AS (
SELECT
Description,
SubDescription,
ROW_NUMBER() OVER ( PARTITION BY Description
ORDER BY Description ) rownumber,
IsOMExceptionRequired,
IsAMB,
IsARS,
escalationtypeid,
CategorySortOrder,
SubcategorySortorder
FROM #Temp
)
SELECT
CASE WHEN Temp.rownumber = 1 THEN Description ELSE '' END [Description],
rownumber,
SubDescription,
CASE WHEN IsOMExceptionRequired = 1 THEN 'YES' ELSE 'N/A' END xxx,
IsAMB,
IsARS,
escalationtypeid,
CategorySortOrder,
SubcategorySortorder
FROM Temp
order by escalationtypeid,CategorySortOrder,SubcategorySortorder;
but actually my result has to be like below.
If you really need to return dynamic column names, build a dynamic query.
Create an nvarchar that contains your query, drawing the column header from the appropriate sources, and execute it with sp_executesql.

SQL Insert row when a cell does not contain a specific set of characters

My database has a column named Group.
This Group can be one of two values:
Group101 = Main group
Group101D1 = Subgroup
Every group has two options like this.
But I have some situations where Group101D1 exists but Group101 does not.
Now I want to create an insert where I search for groups with D1 that doesn't have a main group. for example I have Group105D1 but don't have Group105. I want an insert to create a row with Group105.
This is as far as I have come:
INSERT INTO (Group)
SELECT [Table1].[Group], [Table2].[Group]
FROM [Table] Table1
INNER JOIN [Table] Table2 ON [table1].[Group] = [Table2].[Group]
-- WHERE [Table2].[Group] LIKE '%D1'
-- AND [Table1].[Group] NOT LIKE '%D1'
Can some of you please help, I don't know how to finish this.
I know I probably need to use inner join, replace and a where not clause.
You will need replace Also query should exclude rows already exists
Sample data:
DECLARE #groups TABLE ([Group] VARCHAR(100), description VARCHAR(100))
INSERT #groups ([Group], description)
SELECT 'Group101', 'Something1'
UNION ALL
SELECT 'Group101d1', 'Something1'
UNION ALL
SELECT 'Group105d1', 'description_Bleh'
UNION ALL
SELECT 'Group2054', 'desc_2054'
UNION ALL
SELECT 'Group2054d1', 'desc_2054'
Use replace function and exclude Maingroup if it exists
SELECT Replace([group], 'd1', '') [Group], description
FROM #groups
WHERE [Group] NOT IN (
SELECT p.[Group]
FROM #groups g
INNER JOIN #groups p
ON g.[Group] = replace(p.[Group], 'd1', '')
)
Result:
Group description
Group105 description_Bleh
If all subgroups ends with "D1" you can use below query to insert missing main groups.
INSERT INTO (Group)
SELECT
left(subtable.Group,(len(subtable.Group)-len('D1')))
FROM
[Table1].[Group] subtable
where
charindex ( 'D1', subtable.Group) > 0 -- if it is sub-record
and
not exists --check if main group exists
(SELECT
1
FROM
[Table1].[Group] main
where (charindex ( main.Group+'D1', subtable.Group) != 0)
)
Stuff you have already just packaged with data
DECLARE #groups TABLE (grp VARCHAR(100), description VARCHAR(100));
INSERT #groups (grp, description) values
('Group101', 'Something1')
, ('Group101d1', 'Something1')
, ('Group105d1', 'description_Bleh')
, ('Group106d1', 'description_Bleh6')
, ('Group2054', 'desc_2054')
, ('Group2054d1', 'desc_2054');
select * from #groups order by grp;
insert into #groups
select replace(g1.grp, 'd1', ''), g1.description
from #groups g1
where g1.grp like '%d1'
and not exists ( select 1
from #groups g2
where g2.Grp = replace(g1.grp, 'd1', '')
);
select * from #groups order by grp;
You can use NOT EXISTS and REPLACE to get the desired results like below :
INSERT INTO Table2(Group)
select replace([Group], 'd1', '') from Table1 a
where [Group] like '%d1' and
not exists(
select 1 from Table1 where [group] = replace(a.[Group], 'd1', '')
)
I did it this way in the end!
insert into Table (Group, Description)
select replace(Group,'D1','') , description from Table
where Group like '%D1'
and replace(Group,'D1','') not in (
select Group from Table
where Group like 'Group%' and Group not like '%D1')

INSERT INTO from SELECT: The select list for the INSERT statement contains more items than the insert list

I am still getting a weird error:
The select list for the INSERT statement contains more items than the insert list. The number of SELECT values must match the number of INSERT columns.
Code:
INSERT INTO #tab (Phone)
select t2.Phone
from
(
SELECT DISTINCT top 999 t3.Phone, MIN(t3.Ord)
FROM
(
select Phone1 as Phone, Ord from #tabTemp
union all
select Phone2 as Phone, Ord from #tabTemp
) t3
GROUP BY t3.Phone
ORDER BY MIN(t3.Ord) asc, t3.Phone
) t2
The idea is to select all phone numbers from #tabTemp with their row order. Then I wanna distinct them and insert distincted numbers into table #tab. Top 999 is here only for order by purpose, because I use it into a function (UDF).
Structures are following:
declare #tabTemp TABLE
(
Phone1 varchar(128) NULL,
Phone2 varchar(128) NULL,
Ord int
);
declate #tab TABLE
(
Phone varchar(max) NULL
);
EDITED:
FULL CODE
CREATE FUNCTION dbo.myFnc(#PID int, #VID int, #JID int, #ColumnNo int)
RETURNS #tab TABLE
(
Phone varchar(max) NULL
)
AS
BEGIN
if #PID is null and #VID is null and #JID is null
return;
if #ColumnNo is null or (#ColumnNo<>2 and #ColumnNo<>3 and #ColumnNo<>6)
return;
declare #catH int;
set #catH = dbo.fncGetCategoryID('H','tt'); -- just returning int value
declare #kvalP int;
set #kvalP = dbo.fncGetCategoryID('P','te');
declare #kvalR int;
set #kvalR = dbo.fncGetCategoryID('R','te');
declare #tabTemp TABLE
(
Phone1 varchar(128) NULL,
Phone2 varchar(128) NULL,
Ord int
);
-- finding parent subject + current one
WITH subj AS(
SELECT *
FROM Subjekt
WHERE
(ID = #PID and #PID is not null)
or
(ID = #VID and #VID is not null)
or
(ID = #JID and #JID is not null)
UNION ALL
SELECT t.*
FROM Subjekt t
INNER JOIN subj r ON r.ID = t.ID
)
INSERT INTO #tabTemp (Phone1,Phone2)
(select
(case when o.TYP1=#catH then o.TEL1 else null end) Phone1
,(case when o.TYP2=#catH then o.TEL2 else null end) Phone2
,so.POR_C
from
subj s
,SubjektPerson so
,Persons o
,recSetup idS
,recSetup idSO
,recSetup idO
where 1=1
and idO.isValid=1
and idSO.isValid=1
and idS.isValid=1
and idSO.ID0=so.ID
and idS.ID0=s.ID
and idO.ID0=o.ID
and so.ID_PERSON=o.ID
and so.ID_SUBJECT=s.ID
and (o.TYP=#kvalP or o.TYP=#kvalR)
)
INSERT INTO #tab (Phone)
select t2.Phone
from
(
SELECT DISTINCT top 999 t3.Phone, MIN(t3.Ord)
FROM
(
select Phone1 as Phone, Ord from #tabTemp
union all
select Phone2 as Phone, Ord from #tabTemp
) t3
GROUP BY t3.Phone
ORDER BY MIN(t3.Ord) asc, t3.Phone
) t2
RETURN
END
Not sure why you have distinct AND a group by on the same query. You could greatly simplify this.
INSERT INTO #tab (Phone)
SELECT top 999 t3.Phone
FROM
(
select Phone1 as Phone, Ord from #tabTemp
union all
select Phone2 as Phone, Ord from #tabTemp
) t3
GROUP BY t3.Phone
ORDER BY MIN(t3.Ord) asc, t3.Phone
Now for the error message you were receiving, it doesn't seem like it came from this block of code because the syntax is fine and the number of columns matches correctly. I suspect the error is somewhere earlier in your code.
Also, you might want to consider using temp tables instead of table variables since it seems like you have a lot of rows in these tables.
You've focussed on the wrong insert. This is the one with the mismatch:
INSERT INTO #tabTemp (Phone1,Phone2)
(select
(case when o.TYP1=#catH then o.TEL1 else null end) Phone1
,(case when o.TYP2=#catH then o.TEL2 else null end) Phone2
,so.POR_C
from
...
Two columns in the insert list, 3 columns in the subselect. I can't tell just from the naming whether POR_C was meant to end up in the Ord column or not.
On the surface, it appears you are maybe triggering a query planner bug or something. There are a number of iffy things going on:
The union all of the same table to itself
Using both group by and distinct
I'm not sure what you mean by
Top 999 is here only for order by purpose, because I use it into a function (UDF).
Do you mean this whole query is executed within a UDF? If so, are there other queries that might be giving that error?