Convert rows to columns in SQL Server 2008 - sql

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

Related

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

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

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;

Pivoting multiple transactions per customer

I have a query which gives customer transactional info. Each customer has multiple transactions and designations these transactions go to.The query outputs CustomerId,Amount,Date,Designation. This has multiple rows for each customer.I want to pivot this so that there is only one row per customer.
I know this is not an ideal way to represent this data, but for the purpose of this particular use case, it has to be in this format. The number of columns will be (max of the number of transactions per customer) X 3
To pivot over a fixed list of transactions per client, you could use row_number() and conditional aggregation:
select
CustomerId,
max(case when rn = 1 then Amount end) Amount1,
max(case when rn = 1 then DateReceived end) DateReceived1,
max(case when rn = 1 then Account end) Account1,
max(case when rn = 2 then Amount end) Amount2,
max(case when rn = 2 then DateReceived end) DateReceived2,
max(case when rn = 2 then Account end) Account2,
max(case when rn = 3 then Amount end) Amount3,
max(case when rn = 3 then DateReceived end) DateReceived3,
max(case when rn = 3 then Account end) Account3
from (
select t.*, row_number() over(partition by CustomerId order by DateReceived) rn
from mytable t
) t
group by CustomerId
This handles up to 3 transactions per client. For more, you can expand the select clause with more tuples of max(case when rn = ... then ... end) expressions.

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.

SQL Server transform 3 lines with 3 columns in 9 columns one line

I have this query:
SELECT TOP 3
A.Id,
A.NAME as Name,
B.Rate as PayRate,
C.Description as Currency
FROM
TABLEA A
JOIN
TABLEB B ON A.id = B.TableAId
JOIN
TABLEC C ON B.Id = C.TableBId
WHERE
TABLEA.FieldX = 1
AND TABLEB.FieldX = 3
This returns a result something like this:
Id Name PayRate Currency
-------------------------------------
2503 John 110.00 Dollar
2503 Mike 5.00 EURO
2503 Erik 10.00 Dollar
2504 Rob 2.00 EURO
2504 Elis 11.00 Dollar
2505 May 4.00 Dollar
But I would like to return something like that:
Id Name01 PayRate01 Currency01 Name02 PayRate02 Currency02 Name03 PayRate03 Currency03
--------------------------------------------------------------------------------------------------
2503 John 110.00 Dollar Mike 5.00 EURO Erik 10.00 Dollar
2504 Rob 2.00 EURO Elis 11.00 Dollar Null Null Null
2505 May 4.00 Dollar Null Null Null Null Null Null
It is not fixed query, this is just an example is going to bring many records from the same ID. Some could have 1 line, 2 lines, 3 lines or more lines. So ever ID I want to split into 3 groups of columns.
You should be able to use PIVOT to achieve this result. Please see PIVOT Example from documentation. Something like below...
SELECT id, [0] AS Name01, [1] AS Name02, [2] AS Name03
FROM
(SELECT id, name
FROM table) p
PIVOT
(
name
FOR id IN
( [0], [1], [2] )
) AS pvt
ORDER BY pvt.id;
If the data is fixed then one way to do that is to use case statements like below.
Select
id,
max(case when name='John' then payrate else null end) PayRate01,
max(case when name='John' then currency else null end) Currency01,
max(case when name='John' then name else null end) Name01,
max(case when name='Mike' then payrate else null end) PayRate02,
...
...
from table
group by id
You can use conditional aggregation with row_number():
select id,
max(case when seqnum = 1 then name end) as name_1,
max(case when seqnum = 1 then payrate end) as payrate_1,
max(case when seqnum = 1 then currency end) as currency_1,
max(case when seqnum = 2 then name end) as name_2,
max(case when seqnum = 2 then payrate end) as payrate_2,
max(case when seqnum = 2 then currency end) as currency_2,
max(case when seqnum = 3 then name end) as name_3,
max(case when seqnum = 3 then payrate end) as payrate_3,
max(case when seqnum = 3 then currency end) as currency_3
from (select t.*,
row_number() over (partition by id order by id) as seqnum
from t
) t
group by id;