SQL: How to Transform rows to column in TSQL - sql

Here is table structure, and sample data
create table #tmp ( Id int, Name varchar(100))
insert into #tmp (Id,Name)
Values (1,'Add')
insert into #tmp (Id,Name)
Values (2,'Update')
insert into #tmp (Id,Name)
Values (3,'Delete')
and expected result should be.
Add Update Delete
=== ====== ======
1 2 3

There are several ways that you can transform the data from rows into columns.
If your database has a PIVOT function, then you could use the following code to pivot the data:
select [Add], [Update], [Delete]
from
(
select id, name
from #tmp
) src
pivot
(
max(id)
for name in ([Add], [Update], [Delete])
) piv
See SQL Fiddle with Demo.
Or you could use an aggregate function with a CASE expression:
select
max(case when name = 'Add' then id end) [Add],
max(case when name = 'Update' then id end) [Update],
max(case when name = 'Delete' then id end) [Delete]
from #tmp
See SQL Fiddle with Demo

Please try:
SELECT [Add], [Update], [Delete]
FROM (select * from #tmp) up
PIVOT (sum(id) FOR Name IN ([Add], [Update], [Delete])) AS pvt

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)

How to get the each record with some condition

I have following data:
DECLARE #temp TABLE (
ID int
,sn varchar(200)
,comment varchar(2000)
,rownumber int
)
insert into #temp values(1,'sn1',NULL,1)
insert into #temp values(2,'sn1','aaa',2)
insert into #temp values(3,'sn1','bbb',3)
insert into #temp values(4,'sn1',NULL,4)
insert into #temp values(5,'sn2',NULL,1)
insert into #temp values(6,'sn2',NULL,2)
insert into #temp values(7,'sn2',NULL,3)
select * from #temp
And I want to output like this:
2 sn1 aaa 2
5 sn2 NULL 1
same sn, if comment have value, get this lower rownumber's record. For sn1, have two records with comment value, so here, get the the record with rownumber=2
If comment doesn't have value, get the lower rownumber's record. For sn2, get the record with rownumber=1
May I know how to write this SQL?
This is a prioritization query. I think row_number() is the simplest method:
select t.*
from (select t.*,
row_number() over (partition by sn
order by (case when comment is not null then 1 else 2 end),
rownumber
) as seqnum
from #temp t
) t
where seqnum = 1;
Here is a db<>fiddle.

How to get my required record with defined table

Hi my table structure is shown as below
enter image description here
and with sql query I want to make it as below structure format
enter image description here
I have to make this with single sql query.
Currently I had made this with excel feature
Can I get any suggestion?
Questionid Response Response
1 HighlyEngaged HighlyEngaged
2 VeryPrepared VeryPrepared
2 VeryPrepared1 VeryPrepared1
to
RowLabels Count of Response
1 1
HighlyEngaged 1
2 2
VeryPrepared 1
VeryPrepared1 1
I have prepared following query, I think it can help you :
DROP TABLE QA
GO
CREATE TABLE QA
(
Questionid INT
,Response VARCHAR(100)
)
INSERT INTO QA
VALUES(1,'HighlyEngaged')
,(2,'VeryPrepared' )
,(5,'Asked' )
,(5,'Priority' )
,(5,'Explained' )
,(8,'Yes' )
,(9,'Set Agenda' )
,(9,'Take Atten' )
,(11,'Assigned')
,(11,'Individual')
,(12,'Predict')
,(12,'Questions')
SELECT
CASE
WHEN Response = '' THEN CAST(QuestionId AS VARCHAR)
ELSE ''
END QId
,Response
,ResponseTotal
FROM (SELECT
QuestionId
,'' Response
,COUNT(Response) ResponseTotal
FROM QA
GROUP BY QuestionId
UNION ALL
SELECT
QuestionId
,Response
,COUNT(1)
FROM QA
GROUP BY QuestionId
,Response) a
ORDER BY QuestionId, CASE
WHEN Response = '' THEN 0
ELSE 1
END
drop table #teee
CREATE TABLE #teee
([Questionid] int, [Response] varchar(13), [Response1] varchar(13))
;
INSERT INTO #teee
([Questionid], [Response], [Response1])
VALUES
(1, 'HighlyEngaged', 'HighlyEngaged'),
(2, 'VeryPrepared', 'VeryPrepared'),
(2, 'VeryPrepared1', 'VeryPrepared1')
;
select res,cnt from (select [Questionid],cast([Questionid]as varchar(100)) res ,count([Response]) cnt from #teee
group by [Questionid]
union all
select [Questionid],cast([Response]as varchar(100)) res,count([Response]) r1 from #teee
group by [Questionid],[Response])a
order by [Questionid],res
the following is an update for the answer given by Yogesh Sharma
select isnull([Response],[Questionid]),total from (select [Questionid], [Response], count(*) total
from #teee t
group by [Questionid], [Response] with rollup) a
where isnull([Response],[Questionid]) is not null
order by [Questionid],1
You can use roll up with aggregation :
select questionid, Response, count(*)
from table t
group by questionid, Response with roll up;

Using case in a aggregate sql query without splitting rows

In ms-sql i am using an aggregate group to filter results by user, i would also like to use case to filter by a row not contained in the aggregate so all the user results are on 1 line. I'm not sure this is possible.
Here is the query below which splits the results into two lines.
select case when col_A='1' then sum(col b) End as Sum1_results,
case when col_A='2' then sum(col_b) End as Sum2_Results, Username from tbl1
group by Username, col_A
example of results is.
Sum1_results | Sum2_results | Username
5499 null John
null 3400 John
Ideally, i would like to just have these results merged into one line for each username if possible.
Any help would be appreciated
You could use:
select Username ,
SUM(case when col_A='1' then col_b End) as Sum1_results,
SUM(case when col_A='2' then col_b End) as Sum2_Results,
from tbl1
group by Username
below Query can do the job
Create table #tmp (col_A CHAR(1),col_b int,Username VARCHAR(10))
INSERT INTO #tmp VALUES('1',5000,'John')
INSERT INTO #tmp VALUES('2',400,'John')
INSERT INTO #tmp VALUES('1',499,'John')
INSERT INTO #tmp VALUES('2',3000,'John')
SELECT * FROM #tmp
select SUM(case when col_A='1' then col_b End) as Sum1_results,
SUM(case when col_A='2' then col_b End) as Sum2_Results,Username
from #tmp
group by col_A,UserName
DROP TABLE #tmp
Results merged into one line for each username.
Create table #tmp (col_A CHAR(1),col_b int,Username VARCHAR(10))
INSERT INTO #tmp VALUES('1',5000,'John')
INSERT INTO #tmp VALUES('2',400,'John')
INSERT INTO #tmp VALUES('1',499,'John')
INSERT INTO #tmp VALUES('2',3000,'John')
SELECT * FROM #tmp
select SUM(case when col_A='1' then col_b End) as Sum1_results,
SUM(case when col_A='2' then col_b End) as Sum2_Results,Username
from #tmp
group by UserName
DROP TABLE #tmp

Custom ordering in TSQL

I need to implement custom ordering for my table. For example I have a table called "TestTest" with values: a, d01, d04, d02, b . I need to select data and order them so that values with "d" will be first and rest will be sorted alphanumerical. So the result would be d01,d02,d03,a,b
Script to create and insert data:
CREATE TABLE TestTest(
Name varchar(200)
)
DELETE FROM TestTest
INSERT INTO TestTest( Name )
VALUES( 'a' )
INSERT INTO TestTest( Name )
VALUES( 'd01');
INSERT INTO TestTest( Name )
VALUES( 'd04');
INSERT INTO TestTest( Name )
VALUES( 'd02');
INSERT INTO TestTest( Name )
VALUES( 'b' );
Thx for any help ;)
Select *
From TestTest
Order By CASE WHEN LEFT(Name,1)='d' THEN 1 ELSE 2 END,Name
SQL Fiddle Demo
Quick soution:
Select *
from TestTest
order by case when Name like 'd%' then 'aaaaa'+Name else Name end
select * from TestTest order by case when Name='d01' then 1
when Name='d02' then 2
when Name ='d04' then 3
end desc