Why is PIVOT returning multiple rows? - sql

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

Related

aliasing pivot column

i am trying to alias the pivot column to scenario1, scenario2, scenario3 instead of 1,2,3. I am getting error.
select *
from (select *
from (select s.campaign_id campaign_id, s.scenario_index scenario_index
from scenario s, campaign c where s.campaign_id = c.campaign_id)
pivot (max(scenario_index)for scenario_index in (1,2,3))
)a
thank you, aggregation gives the result with alias now. The requirement i have is to combine these columns with another query which is
select CASE WHEN AWARD_TYPE = 0 THEN award_rate||' points'
when AWARD_TYPE = 1 then Award_rate||' %'
when award_type=2 then RATIO_POINTS||' points per '||RATIO_MON_UNIT||' AED' End
from points_rule p
where c.pt_basic_rule_id = p.point_rule_id ) as pool_awards,
this query comes as a column and then the scenario1, 2,3 should come as 3 columns with the value of the pool_award based on the campaign_id
Just use conditional aggregation:
select s.campaign_id,
max(case when scenario_index = 1 then 1 end) as scenario1,
max(case when scenario_index = 2 then 1 end) as scenario2,
max(case when scenario_index = 3 then 1 end) as scenario3
from scenario s join
campaign c
on s.campaign_id = c.campaign_id
group by campaign_id;
You can use an alias in IN clause of the PIVOT as follows:
select *
from (select *
from (select s.campaign_id campaign_id, s.scenario_index scenario_index
from scenario s, campaign c where s.campaign_id = c.campaign_id)
pivot (max(scenario_index)for scenario_index in (1 as scenario1,2 as scenario2,3 as scenario3))
)a

Pivot Multiple columns together in SQL

I've table like this
I need to get a result like this
RT Team PI Committed Done-Partial Done-Full
----------------------------------------------------------------
ART1 Team1 10 5 1 3
ART2 Team2 7 5 4 1
-----------------------------------------------------------------------
The way I tried is as follows
;with RecentPI as(
select * from (
select rt,Team,pi,[Finish Date],DENSE_RANK() over( partition by rt order by [Finish Date] desc) PIRank from Schedule_Manual S inner join TFS_ARTs_Teams T on T.ART=S.RT
group by RT,Team,PI,[Finish Date]
)tbl
where PIRank=1
)
select * from (select Obj.RT,Obj.[TFS Team], Obj.Type,Obj.PI,[PI Status] from Objectives Obj inner join RecentPI RP on RP.RT=Obj.RT and RP.Team=Obj.[TFS Team] and RP.PI=Obj.PI) as query
PIVOT (count(type) for [Type] in ([Committed])) p1
PIVOT (Count([PI Status]) for [pi status] in ([Done-Partial],[Done-Full])) p2
But it doesnt seems to be correct and also Im not getting full columns in the query. Sorry Im very beginner with SQL Pivot
You can Use this simple Query...your problem will be solved....
select RT,Team,[PI],
sum(case when [Type] = 'Committed' then 1 else 0 end) AS 'Committed',
sum(case when PIStatus = 'Done-Partial' then 1 else 0 end) AS 'Done-Partial',
sum(case when PIStatus = 'Done-Full' then 1 else 0 end) AS 'Done-Full'
from tbl_Pivot
group by RT,Team,[PI]
Output:-

Pivoting rows to columns

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;

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

Subselect Query Improvement

How can I improve the SQL query below (SQL Server 2008)? I want to try to avoid sub-selects, and I'm using a couple of them to produce results like this
StateId TotalCount SFRCount OtherCount
---------------------------------------------------------
AZ 102 50 52
CA 2931 2750 181
etc...
SELECT
StateId,
COUNT(*) AS TotalCount,
(SELECT COUNT(*) AS Expr1 FROM Property AS P2
WHERE (PropertyTypeId = 1) AND (StateId = P.StateId)) AS SFRCount,
(SELECT COUNT(*) AS Expr1 FROM Property AS P3
WHERE (PropertyTypeId <> 1) AND (StateId = P.StateId)) AS OtherCount
FROM Property AS P
GROUP BY StateId
HAVING (COUNT(*) > 99)
ORDER BY StateId
This may work the same, hard to test without data
SELECT
StateId,
COUNT(*) AS TotalCount,
SUM(CASE WHEN PropertyTypeId = 1 THEN 1 ELSE 0 END) as SFRCount,
SUM(CASE WHEN PropertyTypeId <> 1 THEN 1 ELSE 0 END) as OtherCount
FROM Property AS P
GROUP BY StateId
HAVING (COUNT(*) > 99)
ORDER BY StateId
Your alternative is a single self-join of Property using your WHERE conditions as a join parameter. The OtherCount can be derived by subtracting the TotalCount - SFRCount in a derived query.
Another alternative would be to use the PIVOT function like this:
SELECT StateID, [1] + [2] AS TotalCount, [1] AS SFRCount, [2] AS OtherCount
FROM Property
PIVOT ( COUNT(PropertyTypeID)
FOR PropertyTypeID IN ([1],[2])
) AS pvt
WHERE [1] + [2] > 99
You would need to add an entry for each property type which could be daunting but it is another alternative. Scott has a great answer.
If PropertyTypeId is not null then you could do this with a single join. Count is faster than Sum. But is Count plus Join faster than Sum. The test case below mimics your data. docSVsys has 800,000 rows and there are about 300 unique values for caseID. The Count plus Join in this test case is slightly faster than the Sum. But if I remove the with (nolock) then Sum is about 1/4 faster. You would need to test with your data.
select GETDATE()
go;
select caseID, COUNT(*) as Ttl,
SUM(CASE WHEN mimeType = 'message/rfc822' THEN 1 ELSE 0 END) as SFRCount,
SUM(CASE WHEN mimeType <> 'message/rfc822' THEN 1 ELSE 0 END) as OtherCount,
COUNT(*) - SUM(CASE WHEN mimeType = 'message/rfc822' THEN 1 ELSE 0 END) as OtherCount2
from docSVsys with (nolock)
group by caseID
having COUNT(*) > 1000
select GETDATE()
go;
select docSVsys.caseID, COUNT(*) as Ttl
, COUNT(primaryCount.sID) as priCount
, COUNT(*) - COUNT(primaryCount.sID) as otherCount
from docSVsys with (nolock)
left outer join docSVsys as primaryCount with (nolock)
on primaryCount.sID = docSVsys.sID
and primaryCount.mimeType = 'message/rfc822'
group by docSVsys.caseID
having COUNT(*) > 1000
select GETDATE()
go;