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
Related
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
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;
Team, I have a scenario here.
I need to pick 2 latest record through Hql.
I have tried rownumber but does not seems to be getting expected out put
Select
A.emp_ref_i,
A.last_updt_d,
A.start_date,
case when A.Last_updt_d=max(A.Last_updt_d) over (partition by A.emp_ref_i)
and A.start_date=max(a.start_date) over (partition by A.emp_ref_i)
then 'Y' else 'N' end as Valid_f,
a.CHANGE
from
(
select
distinct(emp_ref_i),
last_updt_d,
start_date,
CHANGE
from
PR) A
Currently getting output as
EMP_REF_I LAST_UPDT_D start_date Valid_f CHANGE
1 123 3/29/2020 2/3/2019 Y CHG3
2 123 3/30/2019 2/4/2018 N CHG2
3 123 3/29/2019 2/4/2018 N CHG1
but required:
EMP_REF_I LAST_UPDT_D start_date Valid_f CHANGE
1 123 3/29/2020 2/3/2019 Y CHG3
2 123 3/30/2019 2/4/2018 N CHG2
Use row_number and filter:
select s.emp_ref_i,
s.last_updt_d,
s.start_date,
case when rn=1 then 'Y' else 'N' end Valid_f,
s.change
from
(
Select
A.*,
row_number() over(partition by A.emp_ref_i order by a.Last_updt_d desc, a.start_date desc) rn
from (...) A
)s
where rn<=2;
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.
I want to calculate unique rankings but I get duplicate rankings
Here's my attempt:
SELECT
TG.EMPCODE,
DENSE_RANK() OVER (ORDER BY TS.COUNT_DEL DESC, TG.COUNT_TG DESC) AS YOUR_RANK
FROM
(SELECT
EmpCode,
SUM(CASE WHEN Tgenerate = 1 THEN 1 ELSE 0 END) AS COUNT_TG
FROM
TBLTGENERATE1
GROUP BY
EMPCODE) TG
INNER JOIN
(SELECT
EMP_CODE,
SUM(CASE WHEN STATUS = 'DELIVERED' THEN 1 ELSE 0 END) AS COUNT_DEL
FROM
TBLSTAT
GROUP BY
EMP_CODE) TS ON TG.EMPCODE = TS.EMP_CODE;
The output I get is like this:
EID Rank
---------
102 1
105 2
101 2
103 3
106 4
There is same rank for 105 and 101.
How do I calculate unique ranking?
Use ROW_NUMBER() instead of DENSE_RANK():
SELECT TG.EMPCODE,
ROW_NUMBER() OVER (ORDER BY TS.COUNT_DEL DESC, TG.COUNT_TG DESC) AS YOUR_RANK
Ties will then be given sequential rankings.