Sql server 使用distinct左连接?

Sql server 使用distinct左连接?,sql-server,Sql Server,最初,我的桌子上有15名员工。其中两个姓相同 如果我让E.MAT_EMP选项保持原样,它工作正常,将有15名员工被选中 如果我删除它(因为我不想显示它),除了行数、Firstname、Lastname和月天数。它返回给我的是14行而不是15行。检查后,它显然是我有相同姓氏/名的行之一 @StartDate date, @EndDate date as begin Declare @D1 date = @StartDate Declare @D2 date = @EndDate Declar

最初,我的桌子上有15名员工。其中两个姓相同

如果我让
E.MAT_EMP
选项保持原样,它工作正常,将有15名员工被选中

如果我删除它(因为我不想显示它),除了行数、Firstname、Lastname和月天数。它返回给我的是14行而不是15行。检查后,它显然是我有相同姓氏/名的行之一

@StartDate date,
@EndDate date

as
begin

Declare @D1 date = @StartDate
Declare @D2 date = @EndDate

Declare @Cols varchar(max) = (Select Stuff((Select ',[' +cast(N as varchar(25))+']' From (Select Top (DateDiff(DAY,@D1,@D2)+1) N=Row_Number() Over (Order By (Select Null)) From  master..spt_values n1) A For XML Path ('')),1,1,'') )
Declare @SQL varchar(max) = '
Declare @D1 date = '''+cast(@D1 as varchar(50))+'''
Declare @D2 date = '''+cast(@D2 as varchar(50))+'''

Select ROW_NUMBER() OVER (ORDER BY LastName ASC) as [N°],*
From  ( 
        Select E.MAT_EMP, NOM_EMP as [LastName],PRENOM_EMP as [FirstName],
              Item      = day(d)
              ,Value     = 
              case when (D between DEBUT_DRC and FIN_DRC) and STATUS_DRC = ''Accepté'' then ''RC'' 
              when (D between DEBUT_DAB and FIN_DAB) and STATUS_DAB = ''Accepté'' then ''ABS'' 
              when (D between DC_DEBUT and DC_FIN) and STATUS_DC = ''Accepté'' then DCon.CODE_TYPE_CONGE
              else '''' 

              end
         From 
         DEMANDE_RECUPERATION DC RIGHT JOIN EMPLOYE E 
         ON DC.MAT_EMP = E.MAT_EMP 

         LEFT JOIN DEMANDE_ABSENCE ABS
         ON E.MAT_EMP = ABS.MAT_EMP 

         LEFT JOIN DEMANDE_CONGE DCon 
         ON E.MAT_EMP = DCon.MAT_EMP 

         Cross Join (
                        Select Top (DateDiff(DAY,@D1,@D2)+1) D=DateAdd(DAY,-1+Row_Number() Over (Order By (Select Null)),@D1) From  master..spt_values n1
                    ) B
       ) src
 Pivot (max(value) for Item in ('+@Cols+') ) pvt
'
Exec(@SQL)
结果如下:


我的目标是简单地删除该列,同时保留15行。

将*替换为要显示的列名,而不要将其从子查询中删除

    Select ROW_NUMBER() OVER (ORDER BY LastName ASC) as [N°], [LastName], [FirstName] /*other needed columns here*/
From  ( 
        Select E.MAT_EMP, NOM_EMP as [LastName],PRENOM_EMP as [FirstName],
              Item      = day(d)
              ,Value     = 
              case when (D between DEBUT_DRC and FIN_DRC) and STATUS_DRC = ''Accepté'' then ''RC'' 
              when (D between DEBUT_DAB and FIN_DAB) and STATUS_DAB = ''Accepté'' then ''ABS'' 
              when (D between DC_DEBUT and DC_FIN) and STATUS_DC = ''Accepté'' then DCon.CODE_TYPE_CONGE
              else '''' 

              end
         From 
         DEMANDE_RECUPERATION DC RIGHT JOIN EMPLOYE E 
         ON DC.MAT_EMP = E.MAT_EMP 

         LEFT JOIN DEMANDE_ABSENCE ABS
         ON E.MAT_EMP = ABS.MAT_EMP 

         LEFT JOIN DEMANDE_CONGE DCon 
         ON E.MAT_EMP = DCon.MAT_EMP 

         Cross Join (
                        Select Top (DateDiff(DAY,@D1,@D2)+1) D=DateAdd(DAY,-1+Row_Number() Over (Order By (Select Null)),@D1) From  master..spt_values n1
                    ) B
       ) src
 Pivot (max(value) for Item in ('+@Cols+') ) pvt

在SELECT语句的最终查询中,指定要显示的列的名称:[N°]、[LastName]、[FirstName],因为*表示要显示以前选择的所有列。

检查这两个透视示例,了解如何按所有非聚合列隐式分组:

IF OBJECT_ID('tempdb..#EmployeeData') IS NOT NULL
    DROP TABLE #EmployeeData

CREATE TABLE #EmployeeData (
    EmployeeID INT,
    EmployeeName VARCHAR(100),
    Type CHAR(1),
    Number INT)

INSERT INTO #EmployeeData (
    EmployeeID,
    EmployeeName,
    Type,
    Number)
VALUES
    (1, 'Mark', 'A', 10),
    (1, 'Mark', 'A', 10),
    (1, 'Mark', 'B', 15),
    (1, 'Mark', 'C', 5),
    (2, 'Leonard', 'A', 10),
    (2, 'Leonard', 'C', 45),
    (3, 'Mary', 'B', 10),
    (3, 'Mary', 'C', 15),
    (3, 'Mary', 'C', 25),
    (3, 'Mary', 'C', 5),
    (4, 'Mary', 'A', 25), -- Diferent ID!
    (4, 'Mary', 'A', 15),
    (4, 'Mary', 'C', 20),
    (4, 'Mary', 'C', 35)
第一支点:

-- Pivot Groups by EmployeeID + EmployeeName (all non-aggregate columns)
SELECT
    P.*
FROM
    #EmployeeData AS S
    PIVOT (
        SUM(S.Number) FOR S.Type IN ([A], [B], [C])
    ) AS P
结果:

EmployeeID  EmployeeName    A       B       C
2           Leonard         10      NULL    45
1           Mark            20      15      5
3           Mary            NULL    10      45
4           Mary            40      NULL    55
EmployeeName    A   B       C
Leonard         10  NULL    45
Mark            20  15      5
Mary            40  10      100
第二支点:

-- Pivot Groups by EmployeeName (only)
;WITH NoEmployeeName AS
(
    SELECT
        E.EmployeeName,
        E.Type,
        E.Number
    FROM
        #EmployeeData AS E
)
SELECT
    P.*
FROM
    NoEmployeeName AS S
    PIVOT (
        SUM(S.Number) FOR S.Type IN ([A], [B], [C])
    ) AS P
结果:

EmployeeID  EmployeeName    A       B       C
2           Leonard         10      NULL    45
1           Mark            20      15      5
3           Mary            NULL    10      45
4           Mary            40      NULL    55
EmployeeName    A   B       C
Leonard         10  NULL    45
Mark            20  15      5
Mary            40  10      100
旋转时,正在旋转的行的值将转换为列名。您可以在
选择中引用这些列名(您可以避免使用
*
):

您需要做的是使用
E.MAT_EMP
(必须在子查询中)进行透视,这样您的员工数据就不会按分组,然后不要在
选择中列出它

Declare @D1 date = CONVERT(DATE, GETDATE() - 5)
Declare @D2 date = CONVERT(DATE, GETDATE())

Declare @Cols varchar(max) = (Select Stuff((Select ',[' +cast(N as varchar(25))+']' From (Select Top (DateDiff(DAY,@D1,@D2)+1) N=Row_Number() Over (Order By (Select Null)) From  master..spt_values n1) A For XML Path ('')),1,1,'') )

Declare @SQL varchar(max) = '
Declare @D1 date = '''+cast(@D1 as varchar(50))+'''
Declare @D2 date = '''+cast(@D2 as varchar(50))+'''

Select 
    ROW_NUMBER() OVER (ORDER BY LastName ASC) as [N°],

    pvt.LastName, -- Grouping columns of pivot operator (without MAT_EMP)
    pvt.FirstName,

    -- New columns result of pivot:
    ' + @Cols + ' 

From  ( 
    Select 
        E.MAT_EMP, 
        NOM_EMP as [LastName],
        PRENOM_EMP as [FirstName],
        Item = day(d),
        Value = case 
            when (D between DEBUT_DRC and FIN_DRC) and STATUS_DRC = ''Accepté'' then ''RC'' 
            when (D between DEBUT_DAB and FIN_DAB) and STATUS_DAB = ''Accepté'' then ''ABS'' 
            when (D between DC_DEBUT and DC_FIN) and STATUS_DC = ''Accepté'' then DCon.CODE_TYPE_CONGE
            else '''' end
    From 
        DEMANDE_RECUPERATION DC 
        RIGHT JOIN EMPLOYE E ON DC.MAT_EMP = E.MAT_EMP 
        LEFT JOIN DEMANDE_ABSENCE ABS ON E.MAT_EMP = ABS.MAT_EMP 
        LEFT JOIN DEMANDE_CONGE DCon ON E.MAT_EMP = DCon.MAT_EMP 
        Cross Join (
            Select Top (DateDiff(DAY,@D1,@D2)+1) 
                D=DateAdd(DAY,-1+Row_Number() Over (Order By (Select Null)),@D1) 
            From  
                master..spt_values n1) B
       ) src
    Pivot (
        max(value) for Item in ('+@Cols+') 
    ) pvt
'

PRINT(@SQL)

-- EXEC (@SQL)
如果打印,这是结果(对于我硬编码的一些示例日期值):


我没有仔细检查,但我相信您的pivot函数是通过所有非聚合列隐式分组的(它总是这样做),并且由于聚合,您正在“丢失”一行。如果您从“src”子查询中删除E.MAT_EMP,那么pivot将仅通过NOM_EMP&PRENOM_EMP分组。因此,如果同一姓氏和名字的MAT_EMP超过1,那么可以预期得到的行数会更少。无论如何,如果外部查询中的
[N°]、*
[N°]、[LastName]、[FirstName]、“++@Cols+”
@EzLo在这种情况下的解决方案是什么?@LukStorms我认为应该是“++@Cols+”,因为它是XML。但这不起作用,我得到了列,但对于表示日期的列,我只得到了一个内有+@Cols+的列。这是起作用的,但我应该如何显示这些天的列?在子查询中命名列,然后在主选择中使用这些名称。谢谢,但正如上面和下面所说的,如何显示其他列?哪些列?您刚才说“我的目标是简单地删除该列,同时保留15行”,如果您引用[Item]和[Value],请尝试将它们放在外部查询中的其他行之后,如[N°]、[LastName]、[FirstName]、pvt.[Item]、pvt.[Value]您可以尝试让“第二个”查询的Select语句按原样执行,并在指定最终列名称的位置进行第三个外部查询。