Pivoting rows to columns - sql

Below is my raw data:
raw data
I want the data to be pivoted as below : pivoted data
select cvid, cid,67554,67555,67556,67557
from #temp2 pivot
(
max(lcd)
for qid in ([67554],[67555],[67556],[67557])
)as P
This is the code I tried. Need help!

Here is a possibility, using fairly generic syntax:
select CVID, CID, sum(case when QID = 67554 then LCD else 0 end) as [67554],
sum(case when QID = 67555 then LCD else 0 end) as [67555],
sum(case when QID = 67556 then LCD else 0 end) as [67556],
sum(case when QID = 67557 then LCD else 0 end) as [67557]
from test1
group by CVID, CID;
I tested this in SSMS for SQL Server 2012.

Two things: Make sure you have a source table to pivot. The source table will include the columns you wish to aggregate. In this case, I have given it the alias 'src'. Second, when you are using numbers as column names, make sure to use brackets. Alternatively, begin the column name with a letter. Example, [67554] as Col_67554. I provided that example in the code.
select cvid, cid,[67554] as Col_67554,[67555],[67556],[67557]
from
(select cvid, cid, lcd, qid from #temp2) as src
pivot
(
max(lcd) for qid in ([67554],[67555],[67556],[67557])
) p

If you are using Oracle SQL, try
select * from (
select cvid, cid, qid, lcd
from #temp2
) a
pivot
(
max(lcd)
for qid in (67554,67555,67556,67557)
) b
order by cvid;

Related

How to use max in with clause to get a single value and use this value in main query with null check

I am unable to write this, please help. Below will give an idea of what I'm trying to achieve.
WITH monthly_data AS
(SELECT MAX(some_date) latest_dt FROM monthly_data
)
SELECT SUM(data)
FROM daily_data
WHERE (monthly_data.latest_dt IS NULL
OR daily_data.some_date > monthly_data.latest_dt)
table: monthly_data
id some_date
007 08-MAY-2018
table: daily_data
some_date data
07-MAY-2018 1
08-MAY-2018 1
09-MAY-2018 1
Expected result
Case 1: 1 row exist in table monthly_data.
Query should return 1.
Case 2: No rows exist in table montly_data.
Query should return 3.
The joins in the above query is incorrect but basically written to give you an idea of what I'm trying to do. Also, when I say no rows exist in table monthly_data, it is simplified explanation. There are other conditions in the actual query that filter out the data.
This has to go in a procedure
Edit
Thanks to #D-Shih I'm in a much better position where I started by using the exist clause query that he has provided.
On performance terms, can we write it in a faster way? Something that can evaluate to below would be fastest I believe
WITH CTE AS
( SELECT MAX(some_date) latest_dt FROM monthly_data
)
SELECT SUM(d.some_data)
FROM daily_data d
WHERE (d.some_date > '08-MAY-2018'
OR '08-MAY-2018' IS NULL)
If I understand correct.I think this will be work.
Due to you didn't provide some sample data and expect result.If that didn't your expect result,you can provide some sample data and expect result,I will edit my answer.
WITH CTE AS (
SELECT Max(some_date) latest_dt
FROM monthly_data
)
SELECT Sum(d.data)
FROM daily_data d
WHERE Exists (
SELECT 1
FROM CTE c
WHERE
d.some_date > c.latest_dt
OR
c.latest_dt IS NULL
)
Edit
You can try use CTE table JOIN on daily_data table
WITH CTE AS (
SELECT Max(some_date) latest_dt
FROM monthly_data
)
SELECT SUM(d.data)
FROM CTE c JOIN daily_data d
ON d.some_date > c.latest_dt OR c.latest_dt IS NULL;
sqlfiddle: http://sqlfiddle.com/#!4/33c64e/28
TRY THIS:
SELECT CASE WHEN SUM(CASE WHEN md.Sdate IS NOT NULL THEN 1 ELSE 0 END) > 0 THEN
SUM(CASE WHEN md.Sdate IS NOT NULL THEN 1 ELSE 0 END)
ELSE
SUM(CASE WHEN md.Sdate IS NULL THEN 1 ELSE 0 END)
END cnt
FROM daily_data dd
LEFT JOIN monthly_data md ON md.Sdate = dd.Sdate
....... {other conditions}

Why is PIVOT returning multiple rows?

I am on SQL 2k12 and stumbling with the PIVOT command.
My data looks like this
source data
I need the output like this
DimQuestion_y_attribute [Q42] [Q13] [Q23]
Q14 0.574 0.508 0.403
Q24 0.117 0.19 0.111
The query I am using is this
select DimQuestionNum_y_Attribute, [Q42],[Q13],[Q23]
from [dbo].[Pearson_Coefficient_Values]
PIVOT
(
SUM(coeff_value) For DimQuestionNum_x_Rating IN ([Q42],[Q13],[Q23])
) p
where surveyid = 1109245
The output I see is this
current output does not match requirements
What am I doing wrong?
as an alternative to PIVOT, you might want to try SUM(CASE) in some cases you will get better performance.
SELECT DimQuestionNum_y_Attribute,
SUM(CASE WHEN DimQuestionNum_x_Rating = 'Q42' THEN coeff_value END) [Q42],
SUM(CASE WHEN DimQuestionNum_x_Rating = 'Q13' THEN coeff_value END) [Q13],
SUM(CASE WHEN DimQuestionNum_x_Rating = 'Q23' THEN coeff_value END) [Q23]
FROM [dbo].[Pearson_Coefficient_Values]
WHERE surveyid = 1109245
GROUP BY DimQuestionNum_y_Attribute
try this
select DimQuestionNum_y_Attribute, [Q42],[Q13],[Q23]
from (select DimQuestionNum_y_Attribute,coeff_value, DimQuestionNum_x_Rating from [dbo].[Pearson_Coefficient_Values] where surveyid = 1109245) tb
PIVOT
(
SUM(coeff_value) For DimQuestionNum_x_Rating IN ([Q42],[Q13],[Q23])
) p

pivot table returns more than 1 row for the same ID

I have a sql code which I am using to do pivot. Code is as follows:
SELECT DISTINCT PersonID
,MAX(pivotColumn1)
,MAX(pivotColumn2) --originally these were in 2 separate rows)
FROM(SELECT srcID, PersonID, detailCode, detailValue) FROM src) AS SrcTbl
PIVOT(MAX(detailValue) FOR detailCode IN ([pivotColumn1],[pivotColumn2])) pvt
GROUP BY PersonID
In the source data the ID has 2 separate rows due to having its own ID which separates the values. I have now pivoted it and its still giving me 2 separate rows for the ID even though i grouped it and used aggregation on the pivot columns. Ay idea whats wrong with the code?
So I have all my possible detailCode listed in the IN clause. So I have null returned when the value is none but I want it all summarised in 1 row. See image below.
If those are all the options of detailCode , you can use conditional aggregation with CASE EXPRESSION instead of Pivot:
SELECT t.personID,
MAX(CASE WHEN t.detailCode = 'cas' then t.detailValue END) as cas,
MAX(CASE WHEN t.detailCode = 'buy' then t.detailValue END) as buy,
MAX(CASE WHEN t.detailCode = 'sel' then t.detailValue END) as sel,
MAX(CASE WHEN t.detailCode = 'pla' then t.detailValue END) as pla
FROM YourTable t
GROUP BY t.personID

How to use Pivot on two columns in sql

I have data like below in my table. Flag is bit and label is varchar.
parentid code label flag
1 abc hello false
1 xyz bye false
1 qrt hi true
I need to fetch the records as
parentid label_abc flag_abc label_xyz flag_xyz label_qrt flag_qrt
I can only fetch only label right now using Pivot, but when i give second aggregate function for flag it gives error (Incorrect syntax near ','.). Is there any way to fetch two columns using Pivot.
I did something like this:
SELECT distinct
parentid
, [abc] as label_abc
, [xyz] as label_xyz
, [qrt] as label_qrt
FROM (
Select
parentid,
label,code
FROM items
) a
Pivot (
Max(label), max (flag)
FOR code in ([abc], [xyz], [qrt]
) as Pvt
I find it a bit tricky to do this using the pivot operator, and a lot easier to use conditional aggregation instead:
select
parentid,
max(case when code = 'abc' then label end) as label_abc,
max(case when code = 'abc' then flag end) as flag_abc,
max(case when code = 'xyz' then label end) as label_xyz,
max(case when code = 'xyz' then flag end) as flag_xyz,
max(case when code = 'qrt' then label end) as label_qrt,
max(case when code = 'qrt' then flag end) as flag_qrt
from (
select parentid, code, label, cast(flag as int) flag
from items
) src
group by parentid;
Sample SQL Fiddle
yes, but they need to be pivoted separately. it takes a little bit of fancy footwork, but it should look more like:
select distinct parentid
, [abc1] as label_abc
, [xyz1] as label_xyz
, [qrt1] as label_qrt
, [abc2] as flag_abc
, [xyz2] as flag_xyz
, [qrt2] as flag_qrt
from (
select parentid
, label
, label + '1' as code1
, label + '2' as code2
from items
) as a
pivot (
max(label) for code1 in ([abc1], [xyz1], [qrt1])
) as pvt1
pivot (
max(flag) for code2 in ([abc2], [xyz2], [qrt2])
) as pvt2

2 Rows to 1 Row - Nested Query

I have a response column that stores 2 different values for a same product based on question 1 and question 2. That creates 2 rows for each product but I want only one row for each product.
Example:
select Product, XNumber from MyTable where QuestionID IN ('Q1','Q2')
result shows:
Product XNumber
Bat abc
Bat abc12
I want it to display like below:
Product Xnumber1 Xnumber2
Bat abc abc12
Please help.
Thanks.
If you always have two different values you can try this:
SELECT a.Product, a.XNumber as XNumber1, b.XNumber as XNumber2
FROM MyTable a
INNER JOIN MyTable b
ON a.Product = b.Product
WHERE a.QuestionId = 'Q1'
AND b.QuestionId = 'Q2'
I assume that XNumber1 is the result for Q1 and Xnumber2 is the result for Q2.
This will work best if you don't have answers for both Q1 and Q2 for all ids
SELECT a.Product, b.XNumber as XNumber1, c.XNumber as XNumber2
FROM (SELECT DISTINCT Product FROM MyTable) a
LEFT JOIN MyTable b ON a.Product = b.Product AND b.QuestionID = 'Q1'
LEFT JOIN MyTable c ON a.Product = c.Product AND c.QuestionID = 'Q2'
This is one way to achieve your expected results. However, it relies on knowing that only xNumber abc and abc12 are the values. If this is not the case, then a dynamic pivot would be likely needed.
SELECT product, max(case when XNumber = 'abc' then xNumber end) as XNumber1,
max(Case when xNumber = 'abc12' then xNumber end) as xNumber2
FROM MyTable
GROUP BY Product
The problem is that SQL needs to know how many columns will be in the result at the time it compiles the SQL. Since the number of columns could be dependent on the data itself (2 rows vs 5 rows) it can't complete the request. Using Dynamic SQL you can find out the number of rows, then pass those values in as the column names which is why the dynamic SQL works.
This will get you two columns, the first will be the product, and the 2nd will be a comma delimited list of xNumbers.
SELECT DISTINCT T.Product,
xNumbers = Stuff((SELECT DISTINCT ', ' + T1.XNumber
FROM MyTable T1
WHERE t.Product = T1.Product
FOR XML PATH ('')),1,1,'')
FROM MyTable T
To get what you want, we need to know how many columns there will be, what to name them, and how to determine which value goes into which column
Been using rank() a lot in current code we have been working on at my day job. So this fun variant came to mind for your solution.
Using rank to get the 1st, 2nd, and 3rd possible item identifier then grouping them to create a simulated pivot
DECLARE #T TABLE (PRODUCT VARCHAR(50), XNumber VARCHAR(50))
INSERT INTO #T VALUES
('Bat','0-12345-98765-6'),
('Bat','0-12345-98767-2'),
('Bat','0-12345-98768-1'),
('Ball','0-12345-98771-6'),
('Ball','0-12345-98772-7'),
('Ball','0-12345-98777-9'),
('Hat','0-12345-98711-6'),
('Hat','0-12345-98712-3'),
('Tee','0-12345-98465-1')
SELECT
PRODUCT,
MAX(CASE WHEN I = 1 THEN XNumber ELSE '' END) AS Xnumber1,
MAX(CASE WHEN I = 2 THEN XNumber ELSE '' END) AS Xnumber2,
MAX(CASE WHEN I = 3 THEN XNumber ELSE '' END) AS Xnumber3
FROM
(
SELECT
PRODUCT,
XNumber,
RANK() OVER(PARTITION BY PRODUCT ORDER BY XNumber) AS I
FROM #T
) AS DATA
GROUP BY
PRODUCT