March 2, 2011 at 11:16 pm
I have like following table with annual reports of employees.
CREATE TABLE demo
(EmpNO tinyint, RYear smallint )
GO
INSERT INTO demo
SELECT 1,2002 UNION ALL
SELECT 1,2001 UNION ALL
SELECT 1,2005 UNION ALL
SELECT 2,2002 UNION ALL
SELECT 2,2006
GO
My task is to get comma separated list of missing years out of years 2001, 2002 and 2003.
The result according to above data would be as
EmpNo MissingYears
1 2003
2 2001,2003
Please suggest optimal method for this task.
Thanks & Regards
Atif
DBDigger Microsoft Data Platform Consultancy.
March 3, 2011 at 12:42 am
Try this:
; WITH DistinctEmpNos (EmpNo) AS
(
SELECT DISTINCT EmpNo
FROM demo
),
YearsAndEmps AS
(
SELECT E.EmpNo , Y.Years
FROM DistinctEmpNos E
CROSS JOIN
(
SELECT 2001 UNION ALL
SELECT 2002 UNION ALL
SELECT 2003
) Y (Years)
),
MissingYearsForEachEMp AS
(
SELECT Yrs.EmpNo ,Yrs.Years
FROM demo dem
RIGHT JOIN YearsAndEmps Yrs
ON dem.EmpNo = Yrs.EmpNo
AND dem.RYear = Yrs.Years
WHERE dem.RYear IS NULL
)
SELECT T_O.EmpNo ,STUFF( CAST ( ( SELECT ','+ cast( Years as varchar) FROM MissingYearsForEachEMp T_I
WHERE T_I.EmpNo = T_O.EmpNo
FOR XML PATH(''),TYPE ) AS VARCHAR(MAX)
) , 1,1,'') MissingYears
FROM MissingYearsForEachEMp T_O
GROUP BY T_O.EmpNo
March 3, 2011 at 1:45 am
Else:
SELECT distinct E.EmpNO,Y.Years As 'Missing Years' --E.EmpNo , Y.Years , d.EmpNO as 'DEmp', d.RYear
FROM demo E
CROSS JOIN
(
SELECT 2001 UNION ALL
SELECT 2002 UNION ALL
SELECT 2003 UNION ALL
SELECT 2004 UNION ALL
SELECT 2005 UNION ALL
SELECT 2006
) Y (Years)
LEFT JOIN demo d
ON E.EmpNo = d.EmpNO
AND Y.Years = d.RYear
where d.RYear is NULL
March 3, 2011 at 7:11 am
This doesn't add anything to ColdCoffee's answer. I just saw the other empty thread before I spotted this one so wrote out my solution (pretty much identical to ColdCoffee)
--Create Dummy table
DECLARE @demo AS TABLE
(EmpNO tinyint, RYear smallint )
INSERT INTO @demo
SELECT 1,2002 UNION ALL
SELECT 1,2001 UNION ALL
SELECT 1,2005 UNION ALL
SELECT 2,2002 UNION ALL
SELECT 2,2006
--Actual solution here
;WITH Years (missYear, maxYear)
AS
(
--Create list of all numbers
SELECT 2001 AS missYear, (SELECT MAX(RYear) FROM @demo )
UNION ALL
SELECT missYear + 1, maxYear
FROM Years
--Only needs to go up to the "Max" value
WHERE missYear < maxYear
),
MissingYears AS
(
SELECT DISTINCT EmpNO, Years.missYear
FROM @demo tbl1, Years
--Grabs the missing values
WHERE missYear NOT IN (SELECT RYear FROM @demo tbl2 WHERE tbl1.EmpNO = tbl2.EmpNO)
)
SELECT DISTINCT fin.EmpNo,
--Finally, put the missing years into a comma deliminated list
STUFF(CAST((SELECT ','+ CAST(missYear AS VARCHAR)
FROM MissingYears start WHERE start.EmpNo = fin.EmpNo
FOR XML PATH(''),TYPE ) AS VARCHAR(MAX)),1,1,'') missYear
FROM MissingYears fin
March 3, 2011 at 7:20 am
Well, I posted a link to a good article in the other thread. But since everyone is posting their code here, here's mine (very similar to you guys...)
DECLARE @demo TABLE (EmpNo tinyint, RYear smallint );
INSERT INTO @demo
SELECT 1,2002 UNION ALL
SELECT 1,2001 UNION ALL
SELECT 1,2005 UNION ALL
SELECT 2,2002 UNION ALL
SELECT 2,2006;
WITH YearsNeeded ([Year]) AS
(
SELECT 2001 UNION ALL
SELECT 2002 UNION ALL
SELECT 2003
), Emps AS
(
SELECT DISTINCT EmpNO
FROM @demo
)
SELECT t.EmpNo,
MissingYears = STUFF((SELECT ',' + CONVERT(CHAR(4),[Year])
FROM YearsNeeded y
WHERE y.Year NOT IN (SELECT RYear
FROM @demo t2
WHERE t2.EmpNo = t.EmpNo)
ORDER BY y.Year
FOR XML PATH(''),TYPE).value('.','varchar(max)'),1,1,'')
FROM Emps t
Wayne
Microsoft Certified Master: SQL Server 2008
Author - SQL Server T-SQL Recipes
March 3, 2011 at 7:53 am
Another one to the box:
select d.EmpNO ,
stuff( cast( (
select ','+ cast( Y.Years as varchar)
from demo demo_inner
RIGHT JOIN
(
SELECT 2001 UNION ALL
SELECT 2002 UNION ALL
SELECT 2003
) Y (Years)
on demo_inner.EmpNO = d.EmpNO
and demo_inner.RYear = Y.Years
where demo_inner.RYear is null
order by Y.Years
for XML path (''),TYpe ) as varchar(max)),1,1,''
) missingyrs
from demo d
group by d.EmpNO
March 3, 2011 at 11:56 pm
This probably is the fastest i could think of 🙂
select d.EmpNO ,
stuff( (replace ( ',2001,2002,2003',cast( (
select distinct ','+ cast( demo_inner.RYear as varchar)
from demo demo_inner
where d.EmpNO = demo_inner.EmpNO and demo_inner.RYear IN (2001,2002,2003)
for XML path (''),TYpe ) as varchar(max)), '')),1,1,'') missingyrs
from demo d
group by d.EmpNO
Viewing 9 posts - 1 through 8 (of 8 total)
You must be logged in to reply to this topic. Login to reply