Converting rows to column values. Unique id with multiple code values - sql

I have this table:
Enc_ID
CPT_CODE
1
123
1
234
2
123
2
456
3
123
and I want this:
Enc_ID
CPT_CODE 1
CPT_CODE 2
CPT_CODE 3
1
123
234
2
123
456
3
123

We can try doing a pivot query with the help of ROW_NUMBER:
WITH cte AS (
SELECT t.*, ROW_NUMBER() OVER (PARTITION BY Enc_ID ORDER BY CPT_CODE) rn
FROM yourTable t
)
SELECT
Enc_ID,
MAX(CASE WHEN rn = 1 THEN CPT_CODE END) AS CPT_CODE_1,
MAX(CASE WHEN rn = 2 THEN CPT_CODE END) AS CPT_CODE_2,
MAX(CASE WHEN rn = 3 THEN CPT_CODE END) AS CPT_CODE_3
FROM cte
GROUP BY
Enc_ID;

Related

Convert rows to columns in SQL Server 2008

We have one table called Licenses. This is what it looks like:
CustNum
LicenseAddress
License
ExpiryDate
155
123
Y32CA
12/31/2018
155
998
Y32CB
12/31/2020
155
568
Y32CC
12/31/2022
Here is what I want it to look like:
LicAddr1
Lic1
ExpiryDate1
LicAddr2
Lic2
ExpiryDate2
LicAddr3
Lic3
ExpiryDate3
123
Y32CA
12/31/2018
998
Y32CB
12/31/2020
568
Y32CC
12/31/2022
Here is the query I have currently, however it’s only returning NULLs:
SELECT LicAddr1,
Lic1,
ExpiryDate1,
LicAddr2,
Lic2,
ExpiryDate2,
LicAddr3,
Lic3,
ExpiryDate3
FROM (SELECT CustNum, LicenseAddress, License, ExpiryDate FROM Licenses) d
PIVOT (
MAX(ExpiryDate)
FOR CustNum IN (LicAddr1, Lic1, ExpiryDate1, LicAddr2, Lic2, ExpiryDate2, LicAddr3, Lic3, ExpiryDate3)
) piv
What am I doing wrong?
PIVOT isn't really what you're after, especially since you're trying to get multiple values from each row (which doesn't work very well with the aggregation PIVOT tries to offer).
I'm assuming here you want the most recent three licenses, in which case we can apply a row number per CustNum, ordered by ExpiryDate (newest first), then flip them so they are left-to-right oldest-to-newest:
;WITH cte AS
(
SELECT CustNum, LicenseAddress, License, ExpiryDate,
rn = ROW_NUMBER() OVER (PARTITION BY CustNum ORDER BY ExpiryDate DESC)
FROM dbo.Licenses
)
SELECT CustNum,
LicAddr1 = MAX(CASE WHEN rn = 3 THEN LicenseAddress END),
Lic1 = MAX(CASE WHEN rn = 3 THEN License END),
ExpiryDate1 = MAX(CASE WHEN rn = 3 THEN ExpiryDate END),
LicAddr2 = MAX(CASE WHEN rn = 2 THEN LicenseAddress END),
Lic2 = MAX(CASE WHEN rn = 2 THEN License END),
ExpiryDate2 = MAX(CASE WHEN rn = 2 THEN ExpiryDate END),
LicAddr3 = MAX(CASE WHEN rn = 1 THEN LicenseAddress END),
Lic3 = MAX(CASE WHEN rn = 1 THEN License END),
ExpiryDate3 = MAX(CASE WHEN rn = 1 THEN ExpiryDate END)
FROM cte
GROUP BY CustNum;
Results:
CustNum
LicAddr1
Lic1
ExpiryDate1
LicAddr2
Lic2
ExpiryDate2
LicAddr3
Lic3
ExpiryDate3
155
123
Y32CA
2018-12-31
998
Y32CB
2020-12-31
568
Y32CC
2022-12-31
Example db<>fiddle

employment data - Pivot table, placing all employment data in one row

Hi so I have table as following
employee id
job
start_dt
1
abc
1/1/2021
1
def
5/1/2021
2
xyz
6/1/2021
2
rfd
8/1/2021
2
hgf
7/1/2021
2
esd
1/1/1999
I was wonder if there's a way I could pivot the table and layup all job and date at the same row,
employee id
job_a
start_dt_ a
job_b
start_dt_b
job_c
start_dt_c
job_d
start_dt_d
job_e
start_dt_e
job_f
start_dt_f
1
abc
1/1/2021
def
5/1/2021
2
xyz
6/1/2021
rfd
8/1/2021
hgf
7/1/2021
esd
1/1/1999
(table name 'JOB')
You can use Conditional Aggregation along with ROW_NUMBER() Analytic function such as
WITH j AS
(
SELECT ROW_NUMBER() OVER (PARTITION BY employee_id ORDER BY start_dt) AS rn,
j.*
FROM job j
)
SELECT employee_id,
MAX(CASE WHEN rn = 1 THEN job END) AS job_a,
MAX(CASE WHEN rn = 1 THEN start_dt END) AS start_dt_a,
MAX(CASE WHEN rn = 2 THEN job END) AS job_b,
MAX(CASE WHEN rn = 2 THEN start_dt END) AS start_dt_b,
MAX(CASE WHEN rn = 3 THEN job END) AS job_c,
MAX(CASE WHEN rn = 3 THEN start_dt END) AS start_dt_c,
MAX(CASE WHEN rn = 4 THEN job END) AS job_d,
MAX(CASE WHEN rn = 4 THEN start_dt END) AS start_dt_d
FROM j
GROUP BY employee_id
ORDER BY employee_id
Demo
P.S. the logic for the sorting for current result set is not clear enough

Spliting GROUP BY results into different columns

I have a column containing date ranges and the number of days passed associated to a specific ID (one to many), based on the number of records associated to it, I want those results split into columns instead of individual rows, so from this:
id_hr dd beg end
----------------------------------------
1 10 05/01/2019 15/01/2019
1 5 03/02/2019 08/02/2019
2 8 07/03/2019 15/03/2019
Could become this:
id_hr dd beg end dd beg end
--------------------------------- ---------------------
1 10 05/01/2019 15/01/2019 5 03/02/2019 08/02/2019
2 8 07/03/2019 15/03/2019
I did the same in a worksheet (pivot table) but the table became as slow as it could get, so I'm looking for a more friendly approach in SQL, I did a CTE which number the associated rows and then select each one and display them in new columns.
;WITH CTE AS(
SELECT PER_PRO, ID_HR, NOM_INC, rut_dv, dias_dur, INI, FIN,
ROW_NUMBER()OVER(PARTITION BY ID_HR ORDER BY SUBIDO) AS RN
FROM dbo.inf_vac WHERE PER_PRO = 201902
)
SELECT ID_HR, NOM_INC, rut_dv,
(case when rn = 1 then DIAS_DUR end) as DIAS_DUR1,
(case when rn = 1 then INI end) as INI1,
(case when rn = 1 then FIN end) as FIN1,
(case when rn = 2 then DIAS_DUR end) as DIAS_DUR2,
(case when rn = 2 then INI end) as INI2,
(case when rn = 2 then FIN end) as FIN2,
(case when rn = 3 then DIAS_DUR end) as DIAS_DUR3,
(case when rn = 3 then INI end) as INI3,
(case when rn = 3 then FIN end) as FIN3
FROM CTE
Which gets me each column on where it should be but not grouped. Using GROUP BY displays an error on the CTE select.
rn id_hr dd beg end dd beg end
----------------------------------- ------------------------
1 1 10 05/01/2019 15/01/2019 NULL NULL NULL
2 1 NULL NULL NULL 5 03/02/2019 08/02/2019
1 2 8 07/03/2019 15/03/2019 NULL NULL NULL
Is there any way to group them on the second select?
You have additional columns in the result set that are not in the query. However, this should work:
SELECT ID_HR,
max(case when rn = 1 then DIAS_DUR end) as DIAS_DUR1,
max(case when rn = 1 then INI end) as INI1,
max(case when rn = 1 then FIN end) as FIN1,
max(case when rn = 2 then DIAS_DUR end) as DIAS_DUR2,
max(case when rn = 2 then INI end) as INI2,
max(case when rn = 2 then FIN end) as FIN2,
max(case when rn = 3 then DIAS_DUR end) as DIAS_DUR3,
max(case when rn = 3 then INI end) as INI3,
max(case when rn = 3 then FIN end) as FIN3
FROM CTE
GROUP BY ID_HR;
Yes, you can GROUP BY all the non-CASE columns, and apply MAX to each of the CASE-expression columns.

How to Generate Row number Partition by two column match in sql

Tbl1
---------------------------------------------------------
Id Date Qty ReOrder
---------------------------------------------------------
1 1-1-18 1 3
2 2-1-18 0 3
3 3-1-18 2 3
4 4-1-18 3< >3
5 5-1-18 2 3
6 6-1-18 0 3
7 7-1-18 1 3
8 8-1-18 0 3
---------------------------------------------------------
I want the result like below
---------------------------------------------------------
Id Date Qty ReOrder
---------------------------------------------------------
1 1-1-18 1 3
5 5-1-18 2 3
---------------------------------------------------------
if ReOrder not same with Qty then date will be same upto after reorder=Qty
You can use cumulative approach with row_number() function :
select top (1) with ties *
from (select *, max(case when qty = reorder then 'v' end) over (order by id desc) grp
from table
) t
order by row_number() over(partition by grp order by id);
Unfortunately this will require SQL Server, But you can also do:
select *
from (select *, row_number() over(partition by grp order by id) seq
from (select *, max(case when qty = reorder then 'v' end) over (order by id desc) grp
from table
) t
) t
where seq = 1;

Select and aggregate last records base on order

I have different versions of the charges in a table. I want to grab and sum the last charge grouped by Type.
So I want to add 9.87, 9.63, 1.65.
I want the Parent ID , sum(9.87 + 9.63 + 1.65) as the results of this query.
We use MSSQL
ID ORDER CHARGES TYPE PARENT ID
1 1 6.45 1 1
2 2 1.25 1 1
3 3 9.87 1 1
4 1 6.54 2 1
5 2 5.64 2 1
6 3 0.84 2 1
7 4 9.63 2 1
8 1 7.33 3 1
9 2 5.65 3 1
10 3 8.65 3 1
11 4 5.14 3 1
12 5 1.65 3 1
WITH recordsList
AS
(
SELECT Type, Charges,
ROW_NUMBER() OVER (PArtition BY TYPE
ORDER BY [ORDER] DESC) rn
FROM tableName
)
SELECT SUM(Charges) totalCharge
FROM recordsLIst
WHERE rn = 1
SQLFiddle Demo
Use row_number() to identify the rows to be summed, and then sum them:
select SUM(charges)
from (select t.*,
ROW_NUMBER() over (PARTITION by type order by id desc) as seqnum
from t
) t
where seqnum = 1
Alternatively you could use a window aggregate MAX():
SELECT SUM(Charges)
FROM (
SELECT
[ORDER],
Charges,
MaxOrder = MAX([ORDER]) OVER (PARTITION BY [TYPE])
FROM atable
) s
WHERE [ORDER] = MaxOrder
;
SELECT t.PARENT_ID, SUM(t.CHARGES)
FROM dbo.test73 t
WHERE EXISTS (
SELECT 1
FROM dbo.test73
WHERE [TYPE] = t.[TYPE]
HAVING MAX([ORDER]) = t.[ORDER]
)
GROUP BY t.PARENT_ID
Demo on SQLFiddle