如何使用给定条件在一列中选择多行

Joy*_*rya 6 sql sql-server

员工表

Id      Name
-------------
1        Joy
2       Moni
3       Evan
4      farhad
Run Code Online (Sandbox Code Playgroud)

缺席表

Date(y/m/d)   Id
-----------------
2015/1/1      1
2015/1/3      1
2015/1/4      1
2015/1/5      1
2015/1/1      2
2015/1/4      2
2015/1/5      2
2015/1/5      3
Run Code Online (Sandbox Code Playgroud)

我需要来自上面两个表的数据,如下所示

Name              Date
Joy     2015/1/5, 2015/1/4, 2015/1/3    
Moni    2015/1/5, 2015/1/4
Evan    2015/1/5
Run Code Online (Sandbox Code Playgroud)

第1点:我不会约会,2015/1/1因为2015/1/2员工身份'1'的日期缺失日期表中的欢乐
点2:我不会把日期'2015/1/1',因为日期'2015/1/3'和'2015对于日期表中的moni,员工ID"2"缺少/ 1/2

我已经尝试过像这样的问题,这对我的问题很好,但它需要两倍的大数据执行时间.我怎么能以另一种方式做到这一点,以便我将获得最短的执行时间.

select a.Id,a.name , [dbo].[hello] ('2015/1/1','2015/1/5',a.Id)  From
Employee a

    ALTER FUNCTION [dbo].[hello](@start datetime,@End datetime,@Id int)
    returns varchar(1111)
AS

begin
declare
        @TempDate  DateTime,
        @CombainedDate  varchar(1111)= '',


        while(@End>=@start)

        begin


          select @ TempDate  = (select distinct Date from Absent  d where Date=@End and EmployeeId=@Id)

           if
            @ TempDate  = @End
            begin
           set @End = DATEADD(day, -1, @End)
           set @ CombainedDate  +=  ',' + cast(@TempDate  as varchar(1111)) 
          end
            else
            begin
            break
            end
           end
       return @ CombainedDate  
        end                                                                                           
Run Code Online (Sandbox Code Playgroud)

Joy*_*rya 2

代码(修改修改Giorgi Nakeuri的解决方案)

DECLARE @sd DATETIME,
    @ed DATETIME 
SET @sd = '20150101' 
SET @ed = '20150106'

DECLARE @e TABLE
(
  ID INT ,
  Name NVARCHAR(MAX)
)

INSERT  INTO @e
  SELECT  1, 'Joy' 
UNION 
SELECT  2, 'Moni' 
UNION 
SELECT  3, 'Evan'
UNION 
SELECT 4, 'Farhad'




DECLARE @a TABLE ( ID INT, d DATETIME )

INSERT  INTO @a (ID, D)
        SELECT  1, '20150101'
        union
        SELECT  1, '20150103'
        union
        SELECT  1, '20150104'
        union
        SELECT  1, '20150105'
        union
        SELECT  2, '20150101'
        union
        SELECT  2, '20150104'
        union
        SELECT  2, '20150105'
        union
        SELECT  3, '20150105';

   DECLARE @T TABLE ( ID INT, d DATETIME )
   INSERT INTO @T(ID,d)
   SELECT X.ID, X.D FROM
  (SELECT ID,d FROM @a
   WHERE d BETWEEN @sd AND @ed) X
 INNER JOIN
(SELECT ID, d FROM @a
WHERE d = @ed) Y  ON X.ID=Y.ID;


WITH    cte
      AS ( SELECT   ID ,
                    sd = MIN(d) ,
                    ed = MAX(d) ,
                    ROW_NUMBER() OVER ( PARTITION BY ID ORDER BY MAX(d)
                                        - MIN(d) DESC, MAX(d) DESC ) AS rn
           FROM     ( SELECT    ID ,
                                CAST(d AS INT) AS d ,
                                rn = CAST(d AS INT)
                                - ROW_NUMBER() OVER ( PARTITION BY ID ORDER BY d )
                      FROM      @T
                      WHERE     d >= @sd
                                AND d <= @ed
                    ) a
           GROUP BY ID ,
                    rn
         )
SELECT  e.Name ,
        ( SELECT    STUFF((SELECT   ',' + CONVERT(NVARCHAR(8), d, 112)
                           FROM     @T a WHERE a.ID = c.ID AND a.d >= c.sd AND a.d <= c.ed
                           ORDER BY d desc
                    FOR   XML PATH('') ,
                              TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
        ) AS Date
FROM    cte c
        JOIN @e e ON e.ID = c.ID
WHERE   rn = 1
Run Code Online (Sandbox Code Playgroud)