Sql Issue with Survey results - sql

Hi I have a query returning this
member_id question_variable response_id label
----------- -------------------------------------------------- ----------- ----------------------------
35 area 15 Sydney (Metro)
35 relationship_status 8 Single
35 education 31 Bachelor Degree
35 house_hold_income 4 $75,001 to $100,000
35 pets 36 Dog
35 pets 37 Fish
How do i detect duplicate results such as pets and have response_id = 36,37 and label = Dog, Fish
like so
member_id question_variable response_id label
----------- -------------------------------------------------- ----------- ----------------------------
35 area 15 Sydney (Metro)
35 relationship_status 8 Single
35 education 31 Bachelor Degree
35 house_hold_income 4 $75,001 to $100,000
35 pets 36,37 Dog,Fish

You have to use the keyword STUFF to get the above result.
QUERY:
SELECT DISTINCT T1.MEMBER_ID,T1.QUESTION_VARIABLE,
STUFF((SELECT DISTINCT ',' + T2.RESPONSE_ID
FROM TEST T2
WHERE T1.QUESTION_VARIABLE = T2.QUESTION_VARIABLE
FOR XML PATH('') ),1,1,'') AS RESPONSE_ID,
STUFF((SELECT DISTINCT ',' + T2.LABEL
FROM TEST T2
WHERE T1.QUESTION_VARIABLE = T2.QUESTION_VARIABLE
FOR XML PATH('') ),1,1,'') AS LABEL
FROM TEST T1
;
HERE IS THE LINK TO SQL FIDDLE
http://sqlfiddle.com/#!3/64515/3

This is can be achieved in the following way as well. I haven't got a chance to test this against large data set.
If you want to check the performance, please turn on the following
SET STATISTICS IO ON
SET STATISTICS TIME ON
Query:
SELECT Main.member_id,
Main.question_variable,
STUFF(SubResponse.response_id,1,1,'') AS response_id,
STUFF(SubLebel.label,1,1,'') AS label
FROM Member Main
CROSS APPLY
(
SELECT ',' + response_id
FROM Member
WHERE member_id = Main.member_id AND question_variable = Main.question_variable
FOR XML PATH('')
) SubResponse (response_id)
CROSS APPLY
(
SELECT ',' + label
FROM Member
WHERE member_id = Main.member_id AND question_variable = Main.question_variable
FOR XML PATH('')
) SubLebel (label)
GROUP By Main.member_id,
Main.question_variable,
SubResponse.response_id,
SubLebel.label

SELECT member_id, question_variable, count(*)
FROM MyData
GROUP BY member_id, question_id
HAVING COUNT(*) > 1

Related

Pivot not give expected result

I m using pivot and unpivot but I dot get expected output
Here is my sample data set
Table 1
id c_code
-----------------
123 1
456 1
Table 2
id c_code i_t_code i_code
----------------------
123 1 TWinc 10
123 1 TBinc 20
123 1 TSinc 30
Table 3
i_code i_t_code i_name
------------------------------
10 TWinc abc
20 TBinc xyz
30 TSinc pqr
Here is my query
Query
select * from (
select id,inc,i_t_code from (
select a.id,b.i_name,cast(b.i_code AS
VARCHAR(128)) as i_code,b.i_t_code
from
table_1 a
join
table_2 b
on a.id= b.id
and
a.c_code = b.c_code
join
tabl_3 c on c.i_code = b.i_code
and
c.i_t_code = b.i_t_code
on a.i_code = b.i_code
) d
Unpivot
(
inc for details in (i_name,i_code)
) as unpt) as uppt_res
PIVOT
(
max(inc)
FOR [i_t_code] IN ([TWinc],[TBinc],[TSinc])
) AS P
Expected output:
id TWinc_n TWinc_c TBinc_n TBinc_c TSinc_n TSinc_c
------------------------------------------------------------
123 abc 10 xyz 20 pqr 30
Actual output:
id TWinc TBinc TSinc
------------------------------------
123 abc xyz pqr
How can do this ??
It is possible using pivot or any other solution is there
can anyone help to fix this ?
You're going to have to give your data some variation if you want to stop pivot from compressing equal data items together when it's converting row data into column names and picking the max(inc) - probably easiest to do by changing the contents of the unpivoted data, tacking on a row number:
SELECT * FROM
(
select stoneid, inc, CONCAT(inclusion_type_id, ROW_NUMBER()OVER(PARTITION BY inclusion_type_id ORDER BY inc)) as inclusion_type_id FROM
(
select
a.stoneid,
b.inclusion_name,
cast(b.inclusion_code AS VARCHAR(128)) as inclusion_code,
b.inclusion_type_id,
b.inclusion_type_code
from
PACKET.STONE_LAB_INCLUSIONS a
inner join
MASTER.INCLUSION_MASTER b
on
a.inclusion_code = b.inclusion_code and
a.inclusion_type_code = b.inclusion_type_code
inner join
packet.stone_details c
on
c.stoneid = a.stoneid and
c.certificate_code = a.certificate_code
) d
UNPIVOT(inc for details in (inclusion_name,inclusion_code)) as unpt
) uppt_res
PIVOT
(
MAX(inc)
FOR [inclusion_type_id] IN ([TWinc1],[TWinc2],[TBinc1],[TBinc2],[TSinc1],[TSinc2])
) AS P
If you're desperate to have column names the same, you can alias the results of this query rather than select *

Listing all parents hierarchy in delimited string excluding the top most node

Im having a trouble with an already answered question in stackoverflow itself (Question before). So Im just repeating the question with some changes and a trouble in it because of a root element
I have an SQL table like this
ID Name ParentID
------------------------------
0 Users NULL
1 Alex 0
2 John 0
3 Don 1
4 Philip 2
5 Shiva 2
6 San 3
7 Antony 6
8 Mathew 2
9 Cyril 8
10 Johan 9
-------------------------
Am looking for an out put like this
if I pass the ID 7,10,1
The out put table will be
ID Name Relation
------------------------------------
7 Antony Alex->Don->San->Antony
10 Johan John->Mathew->Cyril->Johan
1 Alex -
From the above answer what I was trying to emphasis is it should not consider the top most node Users whose ID is 0 and parentid is null. So for ID 1, it returned just an empty string for relation or just hyphen (-)
How can I achieve that using CTE
Based on prev answer:
DECLARE #t table (ID int not null, Name varchar(19) not null, ParentID int null)
insert into #t(ID,Name,ParentID) values
(1 ,'Alex',null),
(2 ,'John',null),
(3 ,'Don',1),
(4 ,'Philip',2),
(5 ,'Shiva',2),
(6 ,'San',3),
(7 ,'Antony',6),
(8 ,'Mathew',2),
(9 ,'Cyril',8),
(10,'Johan',9)
declare #search table (ID int not null)
insert into #search (ID) values (7),(10), (1);
;With Paths as (
select s.ID as RootID,t.ID,t.ParentID,t.Name
, CASE WHEN t.ParentId IS NULL THEN '-'
ELSE CONVERT(varchar(max),t.Name) END as Path
from #search s
join #t t
on s.ID = t.ID
union all
select p.RootID,t.ID,t.ParentID,p.Name, t.Name + '->' + p.Path
from Paths p
join #t t
on p.ParentID = t.ID
)
select *
from Paths
where ParentID is null;
Rextester Demo
Based on your schema and data, this query:
with P as
(
select *, cast(null as nvarchar) as chain from People where parentID is null
union all
select C.*, cast(coalesce(P.chain, P.name) + '->' + C.name as nvarchar)
from People C inner join P on C.parentID = P.id
)
select id, name, coalesce(chain, '-') relation from P where id in (7, 10, 1)
Yields:
id name relation
----- ------ ------------------------------
1 Alex -
10 Johan John->Mathew->Cyril->Johan
7 Antony Alex->Don->San->Antony
Rextester Demo.

Filter out rows returned in subquery

I have a temp table that stores rollup data and would like to create a query to see if I could clean up the data a little bit. I thought it would be pretty easy but it has turned out to be much more difficult. Maybe it is easy and I'm just approaching it all wrong.
What I'm trying to do is simply remove rows where Item = 'TOTALS' but where a name only shows up twice. So in the table below, rows 7 and 9 should be removed. Just so you know, there are no keys.
Name . Item ......Dlvrd
--------------------------
Bob . 102 .......... 18
Bob . 106 .......... 32
Bob . 108 .......... 34
Bob . 999 .......... 184
Bob .. TOTALS . 702
John . 64 ........... 86
John . TOTALS . 86
Jim .. 112 .......... 131
Jim .. TOTALS .. 131
Jane . 10 .......... 720
Jane . 12 ........ . 217
Jane . 999 ........ 867
Jane . TOTALS 1848
My first attempt consisted of adding a column with the count of the name column, then using a where clause like: where name != '2' and Item != 'TOTALS'. Didn't work, even putting parenthesis around them. It just removes any row with a 2 or where Item = 'TOTALS'. It's totally ignoring the 'AND'. Here my sql:
select t.count, tr.*
From #TempRollup tr
join (
select
Name
, COUNT(Name) count
from #TempRollup
Group by Name
) as t on t.Name = tr.Name
where (
t.count != 2
and Item != 'TOTALS'
)
Then I tried this method that involves creating a subquery to find the rows I want to ignore and then just not selecting them. My subquery grabs the correct rows but when the whole thing is run, nothing is returned.:
Select *
FROM #TempRollup
WHERE NOT EXISTS(
select tr.*
From #TempRollup tr
join (
select
Name
, COUNT(Name) count
from #TempRollup
Group by Name
) as t on t.Name = tr.Name
where t.count = 2
and Item = 'TOTALS'
)
Try this:
SELECT t.*
FROM #TempRollup t
INNER JOIN
(
SELECT Name, COUNT(*) cnt
FROM #TempRollup
GROUP BY Name
) counts ON t.Name = counts.Name
WHERE t.Item <> 'TOTALS' OR counts.cnt <> 2
SQL Fiddle example
This works for me:
select * from #TempRollup t
where 2 <> (select count(Name) from #TempRollup where Name = t.Name)
and Item <> ' TOTALS';

Concatenating column values from table-2 based on the value from table -1 [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Combining rows of queried results by unique identifier?
I have two tables in Sql Server 2008, like below
Table1
DealNum DealVresion Value
1000 1 100
1000 2 200
1000 3 150
1000 4 130
1001 2 70
1003 5 160
1003 0 120
Table 2
DealNum DealVersion Name
1000 1 John
1000 1 Bob
1000 2 John
1000 2 Merle
1000 3 Bob
1000 3 Bob
1000 5 Bob
1001 2 Smith
1001 2 stone
1002 8 Andrew
1003 5 Smith
1003 0 Martin
1003 0 Narine
Now I want a left join on these two tables based on
(T1.Dealnum= T2.Dealnum) and (T1.Deal Version = T2.Deal Version)
and I want the Name from Table2 to be concatenated so that it won't show any duplicates in DealNum.
Result Required:
DeaLNum Deal Version Value Name
1000 1 100 Jhon,Bob
1000 2 200 John,Merle
1000 3 150 Bob
1000 4 130 NULL
1001 2 70 Smith,Stone
1003 0 120 Martin,Narine
1003 5 160 Smith
It has to concatenate the names column for the DealNum and version.
If the same dealNum and Version has the same name then no need to Concatenate(ex: 1000 - 3)
Thanks In advance
Harry
You can do this by creating a user defined function, don't know if it can be done in a single select statement:
create function getNameList(#dealnum int, #dealversion int) returns nvarchar(max)
begin
declare #name varchar(max)
select #name = coalesce(#name + ', ','') + name
from (select distinct name from table2 where dealnum = #dealnum and dealversion = #dealversion) t1
return #name
end
then:
select distinct
t1.dealNum,
t1.dealVersion,
t1.value,
dbo.getNameList(t1.dealNum, t1.dealversion)
from table1 t1 join table2 t2 on t1.dealnum = t2.dealnum and t1.dealversion = t2.dealversion
try this:
with cte as (
select distinct T1.DealNum [T1_DealNum],T1.DealVresion [T1_DealVresion],
T1.Value [T1_Value],
T2.DealNum [T2_DealNum],T2.DealVresion [T2_DealVresion],T2.Name [T2_Name]
from Table1 T1 left outer join Table2 T2
on (T1.Dealnum= T2.Dealnum) and (T1.DealVresion = T2.DealVresion)
)
select [T1_DealNum],[T1_DealVresion],[Name]=
STUFF((SELECT ', ' + [T2_Name]
FROM cte b
WHERE a.[T1_DealNum]= b.[T2_DealNum]
and a.[T1_DealVresion] = b.[T2_DealVresion]
FOR XML PATH('')), 1, 2, '')
FROM cte a
GROUP BY [T1_DealNum],[T1_DealVresion]
order by [T1_DealNum],[T1_DealVresion]
;WITH y AS
(
SELECT DealNum, DealVersion, Name = STUFF((SELECT ',' + y2.Name
FROM dbo.Table2 AS y2
WHERE y2.DealNum = y.DealNum AND y2.DealVersion = y.DealVersion
GROUP BY y2.Name
FOR XML PATH(''),
TYPE).value(N'./text()[1]', N'nvarchar(max)'), 1, 1, '')
FROM dbo.Table2 AS y
)
SELECT x.DealNum, x.DealVersion, x.Value, y.Name
FROM dbo.Table1 AS x
LEFT OUTER JOIN y
ON x.DealNum = y.DealNum
AND x.DealVersion = y.DealVersion
GROUP BY x.DealNum, x.DealVersion, x.Value, y.Name;

SQL Command combining rows from a field

I am trying to combine rows from one table with my query in MS SQL on server 2008. I pulled this code off here I believe. This almost fits my needs but it is grouping the serial numbers off of SOPartsUsed but I need it to group based off tblServiceOrders.ProjectKeyID. Any help would be greatly appreciated I don't know much about SQL. I will leave a more detailed explanation of what I am trying to accomplish below.
SELECT
p1.ItemID, SerialNumbers AS SerialNumber
FROM
tblSOPartsUsed p1 INNER JOIN
tblServiceOrders p2 ON p1.SONumber = p2.SONumber
CROSS APPLY
(SELECT
stuff
((SELECT ',' + p3.SerialNumber
FROM tblSerialNumbers p3
WHERE p3.FKSOPartsUsed = p1.SOPartsUsedKeyID
ORDER BY SerialNumber FOR XML PATH(''), TYPE ).value('.', 'varchar(max)'), 1, 1, '')
) D (SerialNumbers)
WHERE (p1.QuantityFilled > 0) AND (p2.ProjectKeyID = 385)
GROUP BY p1.ItemID, SerialNumbers, p2.ProjectKeyID
ORDER BY p1.ItemID
I have a table with serial numbers a table with parts used on a service order and a service order table.
tblSerialNumbers -> tblSOPartsUsed -> tblServiceOrders
tblSerialNumbers
itemID SerialNumber FKSOPartsUsed
1 1444 233
1 1555 234
1 1666 236
1 1999 237
1 1888 238
1 2222 239
1 2121 240
tblSOPartsUsed
itemID SOPartsUsed SONumber QuantityFilled
1 233 SO544 5
1 234 SO544 7
1 236 SO544 7
1 237 SO577 7
1 238 SO577 7
1 239 SO581 7
1 240 SO580 7
tblServiceOrders
SOnumber ProjectKeyID
SO544 PJ366
SO577 PJ366
SO580 PJ111
SO581 PJ111
What I would like
itemID ProjectKeyID SerialNumber
1 PJ366 1444,1555,1666,1999,1888
What I get
itemID ProjectKeyID SerialNumber
1 PJ366 1444,1555,1666
1 PJ366 1999,1888
I am trying to group serial numbers and item id's by ProjectKeyID found in tblServiceOrders. Right now the query above works but it is grouping ItemID's on the tblSOPartsUsed and want to group on ProjectKeyID.
Thanks for any help.
SELECT itemID ,
ProjectKeyID ,
( SELECT SerialNumber + ', ' AS 'data()'
FROM dbo.tblSOPartsUsed u
JOIN tblSerialNumbers nbr ON u.SOPartsUsed = nbr.FKSOPartsUsed
WHERE SONumber IN ( SELECT SOnumber
FROM dbo.tblServiceOrders
WHERE ProjectKeyID = tso.ProjectKeyId )
AND itemID = tso.itemID
FOR
XML PATH('')
)
FROM ( SELECT DISTINCT
c.itemID ,
ProjectKeyId
FROM dbo.tblServiceOrders a
JOIN dbo.tblSOPartsUsed b ON a.SOnumber = b.SONumber
JOIN dbo.tblSerialNumbers c ON b.SOPartsUsed = c.FKSOPartsUsed
) tso
I don't think I totally understand what you're trying to accomplish with itemID - having only one distinct value in the sample makes it hard to verify results - but this might get you closer
try this
SELECT
p1.ItemID, p2.ProjectKeyID,D.SerialNumbers AS SerialNumber
FROM
tblSOPartsUsed p1 INNER JOIN
tblServiceOrders p2 ON p1.SONumber = p2.SONumber
CROSS APPLY
(SELECT
stuff
((SELECT ',' + p3.SerialNumber
FROM tblSerialNumbers p3
WHERE p3.ItemID = p1.ItemID
ORDER BY SerialNumber FOR XML PATH(''), TYPE ).value('.', 'varchar(max)'), 1, 1, '')
) D (SerialNumbers)
WHERE (p1.QuantityFilled > 0) AND (p2.ProjectKeyID = 'PJ366')
GROUP BY p1.ItemID, p2.ProjectKeyID, SerialNumbers
ORDER BY p1.ItemID