Data from questions and responses associated to an customer - sql

I have the below data format in my tables, a customer answers test questions and those responses are saved in a table. Questions are grouped as sections. I am trying to get responses associated to a test and for certain sections.
Sectiontable
SecID SecName
1 Box
2 square
3 circle
CustomerTable
CID CName
92 John
93 Andrew
94 Chris
TestTable
testID testkey SecID
18 T1 1
19 T11 1
21 T2 2
22 T21 2
34 T3 3
35 T4 3
CustomerTestresponse
responseID CID testID responseText
1 92 18 T1Text
2 92 19 T11Text
3 92 34 T3Text
4 92 35 T4Text
5 92 22 T21Text
6 93 19 Myresponse
7 93 34 vendor
8 93 21 cutomerout
Expected Query output:
CID T1KeyResponse T11KeyResponse T3KeyResponse T4KeyResponse
92 T1Text T11Text T3Text T4Text
93 Myresponse vendor

It is a FOUR (4) step solution
-- adapted with great reverence from https://dba.stackexchange.com/questions/119844/how-to-pivot-without-fixed-columns-in-tsql
--(1) Declare variables
DECLARE
#cols AS NVARCHAR(MAX)
,#query AS NVARCHAR(MAX)
;
--(2) Concatenate list of new column headers, using FOR XML PATH and STUFF:
-- see Where SecID <> 2 (you may want to change this)
SELECT #cols =
STUFF(
(SELECT DISTINCT
',' + QUOTENAME(t.testkey + 'KeyResponse')
FROM qandrResponse as r
Left Join qandrTest as t
On r.testID = t.testID
Where SecID <> 2 -- you may want to filter differently
Order By ',' + QUOTENAME(t.testkey + 'KeyResponse')
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,''
);
-- Select #cols; -- uncomment to see the list, drag right side open to see full list
--(3) Create the full sql string that will be executed, using #cols from above
set #query
= N'SELECT CID, ' + #cols + N'
From (SELECT
r.CID
,t.testkey + ''' + 'KeyResponse' + N''' as Keys
,responseText
FROM qandrResponse as r
Left Join qandrTest as t
On r.testID = t.testID
) x
Pivot (
max(responseText) for Keys IN (' + #cols + N')
) as p';
-- Select #query; -- uncomment to see sql, prettyprint with http://www.dpriver.com/pp/sqlformat.htm
--(4) Execute the query
exec sp_executesql #query
-- Results
--CID T11KeyResponse T1KeyResponse T3KeyResponse T4KeyResponse
--92 T11Text T1Text T3Text T4Text
--93 Myresponse NULL vendor NULL

Related

SQL PIVOT two tables

I'm trying to sort something out for work where I can get quantity a certain product line from each warehouse. I'm using SAP B1 software
SELECT T0.[ItemCode], [01],[BNE],[SHOP],[Transit]
FROM OITM T0 INNER JOIN OITW T1 ON T0.[ItemCode] = T1.[ItemCode]
PIVOT(SUM(T1.OnHand) FOR T1.WhsCode IN([01],[BNE],[SHOP],[Transit])) AS PivotTable
Group By T0.[ItemCode]
No matter what I attempt to adjust to problem solve, I keep getting more error codes, like comparable types or bound errors... I suppose it is obvious but can anyone help?
This what the data comes in like: (with a few hundred product lines)
Product Code Warehouse Quantity
PROD0001 01 50
BNE 94
Shop 80
Transit 80
-------------------------------------
PROD0002 01 10
BNE 20
Shop 00
Transit 70
-------------------------------------
PROD0003 01 99
BNE 62
Shop 20
Transit 15
And I'm wanting to achieve something like this via a SQL query:
Product Code 01 BNE Shop Transit
PROD0001 50 94 80 80
PROD0002 10 20 00 70
PROD0003 99 62 20 15
Create Table:
create table demo
(
productcode nvarchar(50),
Warehouse nvarchar(50),
Quantity int
);
Insert Table:
insert into demo values
('PROD0001','01','50'),
('PROD0001','BNE','94'),
('PROD0001','Shop','80'),
('PROD0001','Transit','80'),
('PROD0002','01','10'),
('PROD0002','BNE','20'),
('PROD0002','Shop','00'),
('PROD0002','Transit','70'),
('PROD0003','01','99'),
('PROD0003','BNE','62'),
('PROD0003','Shop','20'),
('PROD0003','Transit','15');
SQL Query:
declare #sql as varchar(max);
select #sql = 'select [productcode], ' + stuff((
select distinct ',sum(case [WareHouse] when ' + char(39) + [WareHouse] + char(39) + ' then cast([Quantity] as float) end) as [' + [WareHouse] + ']'
from demo
for xml path('')
)
, 1, 1, ''
);
select #sql += ' from [demo] group by [productcode];';
exec(#sql);

SQL Query rows need to be converted to columns dynamically

Please help me to solve my below query -
I have the following data in my table-
Agent Variable Chandigarh NewDelhi
ABC Leads 102.00 10
ABC TotalTime 10.52 1
ABC RPH 22.79 22
ABC TotalRev 239.70 23
XYZ Leads 14.00 14
XYZ TotalTime 1.52 1
XYZ RPH 21.64 21
XYZ TotalRev 32.90 32
I want the solution like this
Agent Chandigarh_Leads Chandigarh_TotalTime Chandigarh_RPH Chandigarh_RPH_TotalRev NewDelhi_Leads .......
ABC 102.00 10.52 22.79 239.70 10 .......
XYZ 14 1.52 21.64 32.90 14 ............
FYI, I can have more states in columns, it has no limits it may be 10 or 20 or 5 etc. So i need result dynamic query. Please help me, is it possible without static query?
Dynamic SQL + pivoting:
DECLARE #sql nvarchar(max),
#columns nvarchar(max),
#col_to_cast nvarchar(max),
#col_unpvt nvarchar(max)
--This will give:
--,[Chandigarh_Leads],[Chandigarh_RPH]....[NewDelhi_TotalRev],[NewDelhi_TotalTime]
SELECT #columns = COALESCE(#columns,'')+',['+name+'_'+Variable +']'
FROM (
SELECT DISTINCT Variable
FROM #yourtable) v
CROSS JOIN (
SELECT name
FROM sys.columns
WHERE object_id = OBJECT_ID(N'#yourtable')
AND name not in ('Agent', 'Variable')
) c
ORDER BY c.name, v.Variable
--As columns while unpivoting must be same type we need to cast them in same datattype:
--This will give
--,CAST([Chandigarh] as float) as [Chandigarh],CAST([NewDelhi] as float) as [NewDelhi]
SELECT #col_to_cast = COALESCE(#col_to_cast,'')+',CAST(' + QUOTENAME(name)+ ' as float) as '+ QUOTENAME(name)
#col_unpvt = COALESCE(#col_unpvt,'') + ','+ QUOTENAME(name)
FROM sys.columns
WHERE object_id = OBJECT_ID(N'#yourtable')
AND name not in ('Agent', 'Variable')
SELECT #sql = N'
SELECT *
FROM (
SELECT Agent,
[Columns]+''_''+Variable as ColName,
[Values] as ColVal
FROM (
SELECT Agent,
Variable'+#col_to_cast+'
FROM #yourtable
) p
UNPIVOT (
[Values] FOR [Columns] IN ('+STUFF(#col_unpvt,1,1,'')+')
) unpvt
) t
PIVOT (
MAX(ColVal) FOR ColName IN ('+STUFF(#columns,1,1,'')+')
) pvt'
EXEC sp_executesql #sql
Output:
Agent Chandigarh_Leads Chandigarh_RPH Chandigarh_TotalRev Chandigarh_TotalTime NewDelhi_Leads NewDelhi_RPH NewDelhi_TotalRev NewDelhi_TotalTime
ABC 102 22,79 239,7 10,52 10 22 23 1
XYZ 14 21,64 32,9 1,52 14 21 32 1

SQL Pivot - Dynamic Columns, No Aggregation

I'm trying to do a Pivot, but I'm not very experienced with pivots and I'm stuck - I can't figure out how to structure the query.
What I have:
Data Types (types of measurements that are recorded)
Locations
Data Sources (things at each location that will be measured)
Data Readings (measurements of the sources)
Additional information:
The number of Sources at any one Location can change
There will never be more than 5 sources at a single Location
Only 1 Reading is saved per Source/Type/date
In the returned table:
Table shows Data_Type info and Readings for a single Location and date
Columns: Data_Name, Units, Is_Required (from Data_Type table), plus one column for each Source
Rows: one row for each Data_Type
Rows should be ordered by Type_Display_Order
Sources (extra columns) should be ordered by Source_Display_Order
Some Readings are optional, and some Sources aren't measured daily - these still need to be included in the table
Example:
Table: Data_Type
Data_Type_ID Data_Name Units Is_Required (BIT) Type_Display_Order
-----------------------------------------------------------------------
1 Height In. 1 2
2 Length In. 0 3
3 Weight Lbs. 1 1
Table: Location
Location_ID Location
-----------------------
1 West
2 East
Table: Data_Source
Data_Source_ID Location_ID Source_Name Source_Display_Order
----------------------------------------------------------------
1 1 WCS 2
2 2 ECS 1
3 1 WBN 1
Table: Data_Reading
Data_Reading_ID Data_Type_ID Data_Source_ID Reading Reading_Date
----------------------------------------------------------------------
1 1 1 5 6/3/2016
2 3 2 3 5/1/2016
3 1 1 7 5/1/2016
4 2 3 2 6/3/2016
5 3 1 4 6/3/2016
Desired results from query for Location = "West", Date = 6/3/2016:
Data_Type_ID Data_Name Units Is_Required WBN WCS
---------------------------------------------------------
3 Weight Lbs. 1 NULL 4
1 Height In. 1 NULL 5
2 Length In. 0 NULL NULL
This solution seems to be similar: Pivot Dynamic Columns, no Aggregation but I'm still having some problems.
This is what I have so far:
DECLARE #date DATE, #locationID INT
SET #date = CAST('6/3/2016' AS DATE)
SET #locationID = 1
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(s.Source_Name)
FROM Data_Source s
WHERE s.Location_ID = #locationID
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query = 'SELECT Data_Type_ID, Data_Name, Units, Is_Required, ' + #cols +
' FROM
(
SELECT
t.Data_Type_ID
, t.Data_Name
, t.Units
, t.Is_Required
, r.Reading
, s.Source_Name
FROM
Data_Type t
LEFT JOIN
Data_Reading r ON t.Data_Type_ID = r.Data_Type_ID
LEFT JOIN
Data_Source s ON r.Data_Source_ID = s.Data_Source_ID
WHERE
r.Reading_Date = CAST(CAST(' + #date + ' AS NVARCHAR(10)) AS DATE)
AND s.Location_ID = CAST(' + #locationID + ' AS INT)
) x
PIVOT
(
MIN(Reading)
for Source_Name in (' + #cols + ')
) p '
I have the query working properly now, but I still have a few problems:
#cols is not sorted by Source_Display_Order
rows are not sorted by Type_Display_Order (I did have ORDER BY in the inner SELECT statement for part X, but I was getting errors saying I can't have an ORDER BY clause there)
Date comparison in WHERE statement doesn't work - for some reason, it always computes as False, even when the dates are the same
Solved!
DECLARE #date DATE, #locationID INT
SET #date = CAST('6/3/2016' AS DATE)
SET #locationID = 1
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
SET #cols = STUFF((SELECT ',' + QUOTENAME(s.Source_Name)
FROM Data_Source s
WHERE s.Location_ID = #locationID
ORDER BY s.Source_Display_Order
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query =
'SELECT
Data_Type_ID
, Data_Name
, Units
, Is_Required
, ' + #cols + '
FROM
(
SELECT
t.Data_Type_ID
, t.Data_Name
, t.Units
, t.Is_Required
, r.Reading
, s.Source_Name
, t.Type_Display_Order
FROM
Data_Type t
LEFT JOIN
Data_Reading r ON t.Data_Type_ID = r.Data_Type_ID
LEFT JOIN
Data_Source s ON r.Data_Source_ID = s.Data_Source_ID
WHERE
r.Reading_Date = ''' + CAST(#date AS NVARCHAR(10)) + '''
AND s.Location_ID = ' + CAST(#locationID AS NVARCHAR(20)) + '
) x
PIVOT
(
MIN(Reading)
for Source_Name in (' + #cols + ')
) p
ORDER BY
Type_Display_Order'
EXECUTE(#query)
To fix my problems:
Convert #date to NVARCHAR before adding to #query string and include extra quotes to surround the new NVARCHAR in quotes within #query
Remove DISTINCT clause from #cols and add ORDER BY (all of the names in my table are unique, so the DISTINCT is unnecessary)
Add Type_Display_Order to the inner SELECT statement, and add ORDER BY after the PIVOT statement

SQL Server - Dynamic Pivot Query [duplicate]

This question already has answers here:
Efficiently convert rows to columns in sql server
(5 answers)
Closed 7 years ago.
I've been reading the various examples on this board but haven't been able to whip up a dynamic pivot query to fit my code. Any help would be appreciated!
I have two tables
AuxDef
Fieldnumber Fieldlabel
------------------------
1 Buyer
2 Size Range
3 Source
4 Country
5 Vendor
ect... ect...
AuxFields
PageID FieldNumber TextValue
-----------------------------------
1 1 Sam
1 2 S-L
1 3 Domestic
1 4 Canada
2 1 Kyla
2 3 Import
2 5 VendorName
2 6 Off-Shore
2 7 Fit 1
2 8 Yes
4 1 Sara
4 3 Import
4 4 China
ect.. ect.. ect..
What I would like to do is create a dynamic pivot that joins the two tables by fieldnumber and uses the fieldlabels as the column headers after pageid. It would look similar to this.
PageID Buyer Size Range Source Country Vendor Type Status Exclusive ect..
------------------------------------------------------------------------------------------------
1 Sam S-L Domestic Canada
2 Kyla Import VendorName Off-Shore Fit 1 Yes
4 Sara Import China
I've tried examples on this site but I keep running into errors either when I replace the fields with my own or in the actual column generation.
You will need to create a dynamic pivot (credit to #bluefeet's answer here) something like this:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.FieldLabel)
FROM auxdef c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT PageID, ' + #cols + ' from
(
select
PageId,
FieldLabel,
TextValue
from AuxFields af
inner join auxdef ad on af.FieldNumber = ad.FieldNumber
) x
pivot
(
max(TextValue)
for FieldLabel in (' + #cols + ')
) p '
execute(#query);
SQL Fiddle Demo
Here's another way
sql fiddle
declare #sql nvarchar(max)
select #sql = 'select af.pageId'
select #sql = #sql + ', max(case when ad.fieldLabel = ''' + ad.fieldLabel + ''' then af.textValue end) as [' + ad.fieldLabel + ']' + char(13)
from auxDef ad
select #sql = #sql + 'from auxDef ad' + char(13)
+ 'inner join auxFields af on af.fieldNumber = ad.fieldNumber' + char(13)
+ 'group by af.pageId'
exec(#sql)

How do i transform rows into columns in sql server 2005

There is a question here in stackoverflow with the same title but that is not what I am looking for.
I have a table like the one below
Name | Count
----------------
Chery | 257
Drew | 1500
Morgon | 13
Kath | 500
Kirk | 200
Matt | 76
I need to trasform this result set into something like this
Chery | Drew | Morgon | Kath | Kirk | Matt
-------------------------------------------
257 1500 13 500 200 76
How do i acheive this using sql server 2005?
There are similar questions here,here answered in stackoverflow.
You need to use the operator PIVOT in your query to acheive this.Here is the example and explanation on how you can do that.The example is referenced from this source.
---I assumed your tablename as TESTTABLE---
DECLARE #cols NVARCHAR(2000)
DECLARE #query NVARCHAR(4000)
SELECT #cols = STUFF(( SELECT DISTINCT TOP 100 PERCENT
'],[' + t.Name
FROM TESTTABLE AS t
ORDER BY '],[' + t.Name
FOR XML PATH('')
), 1, 2, '') + ']'
SET #query = N'SELECT '+ #cols +' FROM
(SELECT t1.Name , t1.Count FROM TESTTABLE AS t1) p
PIVOT (MAX([Count]) FOR Name IN ( '+ #cols +' ))
AS pvt;'
EXECUTE(#query)
Explanation
1.The first part of the query
SELECT #cols = STUFF(( SELECT DISTINCT TOP 100 PERCENT
'],[' + t.Name
FROM TESTTABLE AS t
ORDER BY '],[' + t.Name
FOR XML PATH('')
), 1, 2, '') + ']'
gives you a nice flattened result of your Name column values in a single row as follow
[Cheryl],[Drew],[Karen],[Kath],[Kirk],[Matt]
You can learn more about the STUFF and XML PATH here and here.
2.SELECT + #cols + FROM will select all the rows as coloumn names for the final result set (pvt - step 3)
i.e
Select [Chery],[Drew],[Morgan],[Kath],[Kirk],[Matt]
3.This query pulls all the rows of data that we need to create the cross-tab results. The (p) after the query is creating a temporary table of the results that can then be used to satisfy the query for step 1.
(SELECT t1.Name, t1.Count FROM TESTTABLE AS t1) p
4.The PIVOT expression
PIVOT (MAX (Count) FOR Name IN ( #cols) AS pvt
does the actual summarization and puts the results into a temporary table called pvt as
Chery | Drew | Morgon | Kath | Kirk | Matt
-------------------------------------------
257 1500 13 500 200 76
See Using PIVOT and UNPIVOT.
You can use the PIVOT and UNPIVOT
relational operators to change a
table-valued expression into another
table. PIVOT rotates a table-valued
expression by turning the unique
values from one column in the
expression into multiple columns in
the output, and performs aggregations
where they are required on any
remaining column values that are
wanted in the final output. UNPIVOT
performs the opposite operation to
PIVOT by rotating columns of a
table-valued expression into column
values.
The quick answer is
SELECT Chery, Drew, Morgon, Kath, Kirk, Matt
FROM
(SELECT [Name], [Count] From Foo)
PIVOT
(
MIN([Count])
FOR [Name] IN (Chery, Drew, Morgon, Kath, Kirk, Matt)
) AS PivotTable
If you want to avoid anything complicated like a pivot or the accepted answer, you can do this! (most of the code is just setting up the test data just in case anyone wants to try it)
/* set up your test table */
declare #TestData table (Name Varchar(80),[Count] int)
insert into #TestData (Name, [count])
Select 'Chery' as name, 257 as [count]
union all select 'Drew', 1500
union all select 'Morgon',13
union all select 'Kath', 500
union all select 'Kirk', 200
union all select 'Matt', 76
/* the query */
Declare #Query Varchar(max)
Select #Query=Coalesce(#query+', ','SELECT ') +Convert(VarChar(5),[count]) +' as ['+name+']'
from #TestData
Execute (#Query)
/* result
Chery Drew Morgon Kath Kirk Matt
----------- ----------- ----------- ----------- ----------- -----------
257 1500 13 500 200 76
*/