DB2 Sql for transpose in Mainframe [closed] - db2

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
want to achieve below the in mainframe Db2 Sql

On Db2 for LUW this will work. Mainframe SQL will be similar. Just use your table name in place of the TABLE(VALUES ... AS(..) bit
SELECT
MAX(CASE WHEN RN = 1 THEN Student_no END) AS Student_no_1
, MAX(CASE WHEN RN = 1 THEN S_Name END) AS S_Name_1
, MAX(CASE WHEN RN = 1 THEN Marks END) AS Marks_1
, MAX(CASE WHEN RN = 2 THEN Student_no END) AS Student_no_2
, MAX(CASE WHEN RN = 2 THEN S_Name END) AS S_Name_2
, MAX(CASE WHEN RN = 2 THEN Marks END) AS Marks_2
, MAX(CASE WHEN RN = 3 THEN Student_no END) AS Student_no_3
, MAX(CASE WHEN RN = 3 THEN S_Name END) AS S_Name_3
, MAX(CASE WHEN RN = 3 THEN Marks END) AS Marks_3
FROM
( SELECT ROW_NUMBER() OVER(ORDER BY Student_no) AS RN
, Student_no
, S_Name
, Marks
FROM
TABLE(VALUES( 2, 'Abc', 89),( 5, 'dfg', 35),( 9, 'qwe', 56))
AS (Student_no, S_Name, Marks)
)
STUDENT_NO_1 S_NAME_1 MARKS_1 STUDENT_NO_2 S_NAME_2 MARKS_2 STUDENT_NO_3 S_NAME_3 MARKS_3
------------ -------- ------- ------------ -------- ------- ------------ -------- -------
2 Abc 89 5 dfg 35 9 qwe 56

Related

Why is there a difference in my SQL output

This is puzzling me no end, and I know it might be tough without the data but thought it might be a longshot to post here.
Here goes, the first code I received was this
USE [Radiotherapy]
GO
if exists (
select * from tempdb.dbo.sysobjects o
where o.xtype in ('U')
and o.id = object_id(N'tempdb..#MySampleTemp')
)
DROP TABLE #MySampleTemp;
if exists (
select * from tempdb.dbo.sysobjects o
where o.xtype in ('U')
and o.id = object_id(N'tempdb..#MyPivotTemp')
)
DROP TABLE #MyPivotTemp;
SELECT [AttendanceNumber]
,CASE WHEN AgeAtExamDate BETWEEN 0 AND 5 THEN '0-5'
WHEN AgeAtExamDate BETWEEN 6 AND 18 THEN '6-18'
WHEN AgeAtExamDate BETWEEN 19 AND 150 THEN '19+'
ELSE 'Error' END AS AgeRange
,[LocalPatientIdentifier]
,[ExaminationDate]
,[ExamExaminationCode] INTO #MySampleTemp
FROM [dbo].[tblRadiologyData]
WHERE AttendanceSiteCode IN('CNM','RNM')
--AND AttendanceStatus NOT IN ( 'Appt', 'Booked In', 'Cancelled', 'Pending' )
--AND AttendancePatientGroup = 'Out Patient'
--AND AttendancePatientCategory IN ( 'EU', 'Military', 'N.H.S.' )
--AND AttendanceSourceName <> 'PACs Support'
AND [ExaminationDate] >= '1 OCTOBER 2015' --
ORDER BY [AttendanceNumber], CASE WHEN AgeAtExamDate BETWEEN 0 AND 5 THEN '0-5'
WHEN AgeAtExamDate BETWEEN 6 AND 18 THEN '6-18'
WHEN AgeAtExamDate BETWEEN 19 AND 150 THEN '19+'
ELSE 'Error' END, [LocalPatientIdentifier], [ExaminationDate], ExamExaminationCode
SELECT [AttendanceNumber],AgeRange,[LocalPatientIdentifier],[ExaminationDate], 1 AS ExamCount,
[1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14] INTO #MyPivotTemp
FROM
(
SELECT *,
row_number() OVER(PARTITION BY [AttendanceNumber]
ORDER BY [AttendanceNumber], [LocalPatientIdentifier]) rn
FROM #MySampleTemp
) AS st
pivot
(
MAX(ExamExaminationCode)
FOR rn in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14])
) AS pivottable
SELECT
[1] AS Exam01,
[2] AS Exam02,
[3] AS Exam03,
[4] AS Exam04,
[5] AS Exam05,
[6] AS Exam06,
[7] AS Exam07,
[8] AS Exam08,
[9] AS Exam09,
[10] AS Exam10,
[11] AS Exam11,
[12] AS Exam12,
[13] AS Exam13,
[14] AS Exam14,
COUNT(ExamCount) AS [No. Attendances]
FROM #MyPivotTemp
GROUP BY [1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14]
ORDER BY [1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14]
What I tried to do was replicate this in query as follows:
USE [Radiotherapy]
;With CTE AS (SELECT s.attendanceNumber,
MAX(CASE WHEN s.rnk = 1 THEN s.ExamExaminationCode END) as examCode1,
MAX(CASE WHEN s.rnk = 2 THEN s.ExamExaminationCode END) as examCode2,
MAX(CASE WHEN s.rnk = 3 THEN s.ExamExaminationCode END) as examCode3,
MAX(CASE WHEN s.rnk = 4 THEN s.ExamExaminationCode END) as examCode4,
MAX(CASE WHEN s.rnk = 5 THEN s.ExamExaminationCode END) as examCode5,
MAX(CASE WHEN s.rnk = 6 THEN s.ExamExaminationCode END) as examCode6,
MAX(CASE WHEN s.rnk = 7 THEN s.ExamExaminationCode END) as examCode7,
MAX(CASE WHEN s.rnk = 8 THEN s.ExamExaminationCode END) as examCode8,
MAX(CASE WHEN s.rnk = 9 THEN s.ExamExaminationCode END) as examCode9,
MAX(CASE WHEN s.rnk = 10 THEN s.ExamExaminationCode END) as examCode10,
MAX(CASE WHEN s.rnk = 11 THEN s.ExamExaminationCode END) as examCode11,
MAX(CASE WHEN s.rnk = 12 THEN s.ExamExaminationCode END) as examCode12,
MAX(CASE WHEN s.rnk = 13 THEN s.ExamExaminationCode END) as examCode13,
MAX(CASE WHEN s.rnk = 14 THEN s.ExamExaminationCode END) as examCode14
FROM (
SELECT [AttendanceNumber]
,[ExaminationDate]
,[ExamExaminationCode]
,ROW_NUMBER() OVER(PARTITION BY [AttendanceNumber]
ORDER BY [RadiologyID]) as rnk --Ordered by date ASC
FROM [Radiotherapy].[dbo].[tblRadiologyData] rd
where rd.ExaminationDate >= '01 october 2015'
and rd.AttendanceSiteCode IN('CNM','RNM') ) s
GROUP BY s.attendanceNumber)
Select CTE.examCode1,
CTE.examCode2,
CTE.examCode3,
CTE.examCode4,
CTE.examCode5,
CTE.examCode6,
CTE.examCode7,
CTE.examCode8,
CTE.examCode9,
CTE.examCode10,
CTE.examCode11,
CTE.examCode12,
CTE.examCode13,
CTE.examCode14,
COUNT(CTE.AttendanceNumber) as [No of occurances]
from CTE
GROUP by CTE.examCode1,
CTE.examCode2,
CTE.examCode3,
CTE.examCode4,
CTE.examCode5,
CTE.examCode6,
CTE.examCode7,
CTE.examCode8,
CTE.examCode9,
CTE.examCode10,
CTE.examCode11,
CTE.examCode12,
CTE.examCode13,
CTE.examCode14
ORDER BY CTE.examCode1
Great I thought until my code returned more results which puzzled me. Having broken it down I found the offending code from the original query:
ORDER BY [AttendanceNumber], CASE WHEN AgeAtExamDate BETWEEN 0 AND 5 THEN '0-5'
WHEN AgeAtExamDate BETWEEN 6 AND 18 THEN '6-18'
WHEN AgeAtExamDate BETWEEN 19 AND 150 THEN '19+'
ELSE 'Error' END, [LocalPatientIdentifier], [ExaminationDate], ExamExaminationCode
When I removed this from the first query the results matched, but my question is how and why is an ORDER BY affecting the output. I assumed this was just showing how the results are ordered? Understanding why code is doing what it's doing is something I really need to get my head around. Any advise more than welcome.
Probably it have something to do with this piece of code:
SELECT *,
row_number() OVER(PARTITION BY [AttendanceNumber]
ORDER BY [AttendanceNumber], [LocalPatientIdentifier]) rn
FROM #MySampleTemp
Obviously your ordering is not breaking a tie(it isn't deterministic) and it produces rank number differently when you have ordered data in temp table and when not ordered. Try to add some PK to your temp table so the above code will look like:
SELECT *,
row_number() OVER(PARTITION BY [AttendanceNumber]
ORDER BY [AttendanceNumber], [LocalPatientIdentifier], [SomePK]) rn
FROM #MySampleTemp
Then removing ordering from first select statement will not have an effect on the result set.

Building totals based on condition in another row

Really struggling to understand the best way of doing this...
I have a table of data
**StudentID AssessmentCode ResultGroup Result**
46933 12ENG IBLevel HL
46933 12ENG Mark 6
46933 12ECO IBLevel HL
46933 12ECO Mark 5
46933 12GEO IBLevel SL
46933 12GEO Mark 6
46933 12LAN IBLevel HL
46933 12LAN Mark 4
46933 12PED IBLevel SL
46933 12PED Mark 5
46933 12SCI IBLevel SL
46933 12SCI Mark 3
67767 12FRE IBLevel HL
67767 12FRE Mark 4
67767 12MAT IBLevel SL
67767 12MAT Mark 5
and so on...
Unfortunately the result column holds 2 different bits of info. The level a student does (HL = High Level; SL = Standard Level) and then the result for that subject at that level. Note that for each student, 2 rows are generated per subject a student does, one row has the IBLevel and the next row has the result for that level.
How can I rearrange the data to get something like
StudentID HLResult SLResult TotalResult CountofHL CountofSL
46933 15 14 29 3 3
67767 13 10 23 4 2
So each student has one row of data with totals for HL, SL, both together and then a count of the number of HL and SL subjects. As I said, really not sure of the best way of going about this. In the end, I would also like to extend this to get some columns which, based on the results give some warning messages eg the TotalResult has to be great than 24 so I would love a column that simply returns whether this has been achieved or not...
StudentID HLResult SLResult TotalResult CountofHL CountofSL MoreThan24
46933 15 14 29 3 3 True
67767 13 10 23 4 2 False
Any help would be greatly appreciated...
Your table seems to have some serious normalization issues. You have to perform an INNER JOIN on AssessmentCode first:
SELECT t1.StudentID, t1.AssessmentCode,
t1.Result AS Level, CAST(t2.Result AS INT) AS Mark
FROM (
SELECT StudentID, AssessmentCode, Result
FROM mytable
WHERE ResultGroup = 'IBLevel' ) AS t1
INNER JOIN (
SELECT StudentID, AssessmentCode, Result
FROM mytable
WHERE ResultGroup = 'Mark' ) AS t2
ON t1.StudentID = t2.StudentID AND t1.AssessmentCode = t2.AssessmentCode
to get one row per AssessmentCode.
Output:
StudentID AssessmentCode Level Mark
-----------------------------------------
46933 12ENG HL 6
46933 12ECO HL 5
46933 12GEO SL 6
46933 12LAN HL 4
46933 12PED SL 5
46933 12SCI SL 3
67767 12FRE HL 4
67767 12MAT SL 5
You can now wrap the above query in a CTE and perform conditional aggregation to get required result:
;WITH CTE AS (
... above query here
)
SELECT StudentID,
SUM(CASE WHEN Level = 'HL' THEN Mark ELSE 0 END) AS HLResult,
SUM(CASE WHEN Level = 'SL' THEN Mark ELSE 0 END) AS SLResult,
SUM(Mark) AS TotalResult,
COUNT(CASE WHEN Level = 'HL' THEN 1 END) AS CountofHL,
COUNT(CASE WHEN Level = 'SL' THEN 1 END) AS CountofSL,
CASE WHEN SUM(Mark) > 24 THEN 'True'
ELSE 'False'
END AS MoreThan24
FROM CTE
GROUP BY StudentID
Output:
StudentID HLResult SLResult TotalResult CountofHL CountofSL MoreThan24
46933 15 14 29 3 3 True
67767 4 5 9 1 1 False
Demo here
My Version of Your Table
DECLARE #yourTable TABLE
(
StudentID INT,
AssessmentCode CHAR(5),
ResultGroup VARCHAR(10),
Result VARCHAR(5)
)
INSERT INTO #yourTable
VALUES (46933,'12ENG','IBLevel','HL'),
(46933,'12ENG','Mark','6'),
(46933,'12ECO','IBLevel','HL'),
(46933,'12ECO','Mark','5'),
(46933,'12GEO','IBLevel','SL'),
(46933,'12GEO','Mark','6'),
(46933,'12LAN','IBLevel','HL'),
(46933,'12LAN','Mark','4'),
(46933,'12PED','IBLevel','SL'),
(46933,'12PED','Mark','5'),
(46933,'12SCI','IBLevel','SL'),
(46933,'12SCI','Mark','3'),
(67767,'12FRE','IBLevel','HL'),
(67767,'12FRE','Mark','4'),
(67767,'12MAT','IBLevel','SL'),
(67767,'12MAT','Mark','5');
Actual Query
WITH CTE_ResultValue
AS
(
SELECT StudentID,
AssessmentCode,
ResultGroup,
CAST(Result AS INT) AS ResultValue
FROM #yourTable
WHERE ISNUMERIC(Result) = 1
),
CTE_IBLevel
AS
(
SELECT StudentID,
AssessmentCode,
Result AS IBLevel
FROM #yourTable
WHERE ISNUMERIC(Result) = 0
),
CTE_Normalized
AS
(
SELECT A.StudentID,
A.AssessmentCode,
A.ResultGroup,
A.ResultValue,
B.IBLevel
FROM CTE_ResultValue AS A
INNER JOIN CTE_IBLevel AS B
ON A.StudentID = B.StudentID
AND A.AssessmentCode = B.AssessmentCode
)
SELECT [StudentID],
[HLResult] = SUM(CASE WHEN IBLevel = 'HL' THEN ResultValue END),
[SLResult] = SUM(CASE WHEN IBLevel = 'SL' THEN ResultValue END),
[TotalResult] = SUM(ResultValue),
[CountOfHL] = SUM(CASE WHEN IBLevel = 'HL' THEN 1 END),
[CountOfSL] = SUM(CASE WHEN IBLevel = 'SL' THEN 1 END)
FROM CTE_Normalized
GROUP BY StudentID
Normalization
Your table is in serious need of normalization. If you can change it, bare minimal change would look like this:
CREATE TABLE dbo.NormalizedTable
(
StudentID INT,
AssessmentCode CHAR(5),
ResultGroup VARCHAR(25),
ResultValue SMALLINT, --smallint range should be plenty. It can store values from -32,768 to 32,767
IBLevel CHAR(2)
)
INSERT INTO dbo.NormalizedTable
SELECT *
FROM CTE_Normalized
If you can't change the way your data is structured, I'd recommend creating a view from my CTE_normalized
CREATE VIEW vw_normalizedTable
AS
WITH CTE_ResultValue
AS
(
SELECT StudentID,
AssessmentCode,
ResultGroup,
CAST(Result AS INT) AS ResultValue
FROM #yourTable
WHERE ISNUMERIC(Result) = 1
),
CTE_IBLevel
AS
(
SELECT StudentID,
AssessmentCode,
Result AS IBLevel
FROM #yourTable
WHERE ISNUMERIC(Result) = 0
),
SELECT A.StudentID,
A.AssessmentCode,
A.ResultGroup,
A.ResultValue,
B.IBLevel
FROM CTE_ResultValue AS A
INNER JOIN CTE_IBLevel AS B
ON A.StudentID = B.StudentID
AND A.AssessmentCode = B.AssessmentCode
GO
Version1:
SELECT t1.StudentID,
SUM(CASE WHEN t1.Result = 'HL' THEN t2.Result ELSE 0 END) HLResult,
SUM(CASE WHEN t1.Result = 'SL' THEN t2.Result ELSE 0 END) SLResult,
SUM(CAST(t2.Result AS INT)) TotalResult,
SUM(CASE WHEN t1.Result = 'HL' THEN 1 ELSE 0 END) CountofHL,
SUM(CASE WHEN t1.Result = 'SL' THEN 1 ELSE 0 END) CountofSL,
CASE WHEN SUM(CAST(t2.Result AS INT)) > 24 THEN 'True' ELSE 'False' END MoreThan24
FROM #t t1
JOIN #t t2 ON t1.StudentID = t2.StudentID AND
t1.AssessmentCode = t2.AssessmentCode AND
t1.ResultGroup = 'IBLevel' AND
t2.ResultGroup = 'Mark'
GROUP BY t1.StudentID
Version2:
WITH cte1 AS(
SELECT *, ROW_NUMBER() OVER(PARTITION BY StudentID, AssessmentCode
ORDER BY CASE WHEN ResultGroup = 'IBLevel' THEN 1 ELSE 2 END) AS rn FROM #t),
cte2 AS(SELECT StudentID,
AssessmentCode,
SUM(CASE WHEN Result = 'HL' THEN 1 ELSE 0 END) HL,
SUM(CASE WHEN Result = 'SL' THEN 1 ELSE 0 END) SL,
MAX(CASE WHEN rn = 2 THEN Result END) R
FROM cte1
GROUP BY StudentID, AssessmentCode)
SELECT StudentID,
SUM(hl*R) HLResult,
SUM(sl*R) SLResult,
SUM((hl + sl)*r) TotalResult,
SUM(hl) CountofHL,
SUM(sl) CountofSL,
CASE WHEN SUM((hl + sl)*r) > 24 THEN 'True' ELSE 'False' END MoreThan24
FROM cte2
GROUP BY StudentID
Output:
StudentID HLResult SLResult TotalResult CountofHL CountofSL MoreThan24
46933 15 14 29 3 3 True
67767 4 5 9 1 1 False
Just replace #t with your table.

SQL select converting transaction rows to columns

I have a table that lists all transactions as follows:
ID Account Date Amount
---------------------------
1 2 02/01/2015 30
2 5 05/01/2015 25
3 2 05/01/2015 12
4 2 07/01/2015 42
5 5 10/012015 19
6 2 11/01/2015 58
7 3 15/01/2015 36
Would like to write a select statement that will list only the last 3 transactions of each account, as follows please.
Account Date1 Amount Date2 Amount Date3 Amount
---------------------------------------------------------------
2 11/01/2015 58 07/01/2015 42 05/01/2015 12
3 15/01/2015 36
5 10/01/2015 19 05/01/2015 25
Thank you for any advice
You can use the row_number() function in a derived table to partition the data by account, and give each date within the partition a number, and then do a conditional aggregation over the rows with the top 3 numbers, grouped by account:
select
account,
date1 = max(case when rn = 1 then date end),
amount = max(case when rn = 1 then amount end),
date2 = max(case when rn = 2 then date end),
amount = max(case when rn = 2 then amount end),
date3 = max(case when rn = 3 then date end),
amount = max(case when rn = 3 then amount end)
from (
select *, rn = row_number() over (partition by account order by date desc)
from your_table
) a
where rn <= 3
group by account
Sample SQL Fiddle

How to get data on a single row

I have table called RUGS with the data below. How do I write a TSQl query to get the data as shown in Output. I am not familiar with unPIVOT
`cono ARtype days Revenue PPD
140 MCD 5 1000 500
140 MRA 6 2000 600
140 MRA 7 3000 700
141 MCD 1 5000 100
141 MRA 2 6000 200
141 MRA 3 7000 300`
Result
140 MCD 5 1000 500 MRA 6 2000 600 MRA 7 3000 700
141 MCD 1 5000 100 MRA 2 6000 200 MRA 3 7000 300
Given that every cono will have exactly 3 records (as stated in the comments), a cte with row_number can be used with case statements.
If any have less than three records, you will see blanks and zeroes in the results. Any with more than three will not have all records represented.
Here is an example with #RUGS as a table variable:
declare #RUGS table (cono int, ARType char(3), [days] int, Revenue int, PPD int)
insert into #RUGS VALUES
(140,'MCD',5,1000,500)
,(140,'MRA',6,2000,600)
,(140,'MRA',7,3000,700)
,(141,'MCD',1,5000,100)
,(141,'MRA',2,6000,200)
,(141,'MRA',3,7000,300);
with cte as
(
select row_number() over(partition by cono order by (select 1)) as rn, * from #RUGS
)
select cono,
max(case when rn = 1 then ARType else '' end) as ARType1,
max(case when rn = 1 then days else '' end) as days1,
max(case when rn = 1 then Revenue else '' end) as Revenue1,
max(case when rn = 1 then PPD else '' end) as PPD1,
max(case when rn = 2 then ARType else '' end) as ARType2,
max(case when rn = 2 then days else '' end) as days2,
max(case when rn = 2 then Revenue else '' end) as Revenue2,
max(case when rn = 2 then PPD else '' end) as PPD2,
max(case when rn = 3 then ARType else '' end) as ARType3,
max(case when rn = 3 then days else '' end) as days3,
max(case when rn = 3 then Revenue else '' end) as Revenue3,
max(case when rn = 3 then PPD else '' end) as PPD3
from cte group by cono

Union Statement that can be changed to Case statement

Good Day Everyone!
well i have this kind of code and it kinda ugly,
a friend of mine told me i can implement Case Statements in here, but i do not know how or how would i implement, the code is long so if you could just help me to optimize my code i would appreciate it greatly!
PS. please be gentle to me, im new in T-sql :)
Thank yoU!
SELECT
SUM(CYJEWELRY) 'CY_Jewelry'
,SUM(CYAPPLICANCE) 'CY_Appliance'
,SUM(CYCELLPHONE) 'CY_Cellphone'
,SUM(PYJEWELRY) 'PY_Jewelry'
,SUM(PYAPPLIANCE) 'PY_Appliance'
,SUM(PYCELLPHONE) 'PY_Cellphone'
FROM
(
---TOTAL NUNG A FORMAT 0,0,0,0,0,0
--------------CURRENT YEAR JEWELRY
SELECT COUNT (*) AS CYJEWELRY,0 AS CYAPPLICANCE,0 AS CYCELLPHONE,0 AS PYJEWELRY,0 AS PYAPPLIANCE,0 AS PYCELLPHONE
FROM #TEMPTABLE1
WHERE (fld_StorageGroupID >= 3 and fld_StorageGroupID <= 14)
UNION
-----------CURRENT YEAR APPLIANCE
SELECT 0,COUNT(*),0,0,0,0
FROM #TEMPTABLE1
WHERE fld_StorageGroupID = 1
UNION
------------CURRENT YEAR CELLPHONE
SELECT 0,0,COUNT(*),0,0,0
FROM #TEMPTABLE1
WHERE fld_StorageGroupID = 2
UNION
---------------LAST YEAR JEWELRY
SELECT 0,0,0,COUNT(*),0,0
FROM #TEMPTABLE2
WHERE (fld_StorageGroupID >= 3 and fld_StorageGroupID <= 14)
UNION
-----------------------LAST YEAR APPLIANCE
SELECT 0,0,0,0,COUNT (*),0
FROM #TEMPTABLE2
WHERE fld_StorageGroupID = 1
UNION
-------------------------LAST YEAR CELLPHONE
SELECT 0,0,0,0,0,COUNT(*)
FROM #TEMPTABLE2
WHERE fld_StorageGroupID = 2
)A
Assuming your data is bit like this Sql Fiddle Example, try this for the sub query using SUM() and CASE.
SELECT SUM(CASE WHEN fld_StorageGroupID >= 3 and fld_StorageGroupID <= 14 ELSE 0 END) Col1And4,
SUM(CASE WHEN fld_StorageGroupID = 1 THEN 1 ELSE 0 END) Col2And5,
SUM(CASE WHEN fld_StorageGroupID = 2 THEN 1 ELSE 0 END) Col3And6
FROM #TEMPTABLE1
GROUP BY fld_StorageGroupID
Since you are applying the same filter for last 3 columns in the subquery, I have done only first 3 columns here.
EDIT:
I think this is better than above (Note: no need to use SUM() in the main query).
Fiddle Example with data
select col1_4 CY_Jewelry,
col2_5 CY_Appliance,
col3_6 CY_Cellphone,
col1_4 PY_Jewelry,
col2_5 PY_Appliance,
col3_6 PY_Cellphone
from (
select sum(case when id>= 3 and id <= 14 then 1 else 0 end) col1_4,
sum(case when id = 2 then 1 else 0 end) col2_5,
sum(case when id = 3 then 1 else 0 end) col3_6
from t
--group by id
) X