【问题标题】:LEFT JOIN Using distinct?LEFT JOIN 使用不同的?
【发布时间】:2018-12-21 16:01:55
【问题描述】:

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

如果我保留E.MAT_EMP 的选择,它可以正常工作,15 名员工将被选中。

如果我删除它(因为我不想显示它),但行数、名字、姓氏和月份日期除外。它返回给我 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 行的同时简单地删除该列。

【问题讨论】:

  • 我没有仔细检查,但我相信您的数据透视函数是按所有非聚合列进行的隐式分组(它总是这样做),并且由于聚合,您正在“丢失”一行。
  • 如果您从“src”子查询中删除 E.MAT_EMP,那么 PIVOT 将仅按 NOM_EMP 和 PRENOM_EMP 分组。因此,如果相同姓氏和名字的 MAT_EMP 超过 1 个,则可以预期获得的行数更少。无论如何,如果将外部查询中的 [N°],* 替换为 [N°], [LastName], [FirstName], '+@Cols+' 会发生什么
  • @EzLo 这种情况有什么解决办法?
  • @LukStorms 我认为它应该是 ''+@Cols+'' 因为它是 XML。但这不起作用,我得到了列,但是对于代表日子的列,我只得到一个里面有 +@Cols+ 的列。

标签: sql-server


【解决方案1】:

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

    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

【讨论】:

  • 这行得通,但我应该如何显示这些天的列?
  • 为子查询中的列命名,然后在主选择中使用这些名称。
【解决方案2】:

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

【讨论】:

  • 谢谢,但如上所述,我怎样才能显示其他列?
  • 哪些?您刚刚说 '我的目标是在保留 15 行的同时简单地删除该列' 如果您引用 [Item] 和 [Value],请尝试将它们放在外部查询中的其他列之后,如下所示[N°], [LastName], [FirstName], pvt.[Item], pvt.[Value]
  • 您可能会尝试让“第二个”查询的 Select 语句保持原样,并在您指定最终列名称的地方进行第三个外部查询。
【解决方案3】:

查看这 2 个数据透视示例,了解 PIVOT 如何按所有非聚合列隐式分组:

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

第二个支点:

-- 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

结果:

EmployeeName    A   B       C
Leonard         10  NULL    45
Mark            20  15      5
Mary            40  10      100

透视时,您正在透视的行的值将转换为列名。您可以在SELECT 上引用这些列名(可以避免使用*):

SELECT
    P.EmployeeID,
    P.EmployeeName,

    P.A, -- Pivot values as column names
    P.B,
    P.C
FROM
    #EmployeeData AS S
    PIVOT (
        SUM(S.Number) FOR S.Type IN ([A], [B], [C])
    ) AS P

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

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)

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

Declare @D1 date = '2018-12-16'
Declare @D2 date = '2018-12-21'

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:
    [1],[2],[3],[4],[5],[6] 

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 ([1],[2],[3],[4],[5],[6]) 
    ) pvt

【讨论】:

    猜你喜欢
    • 2017-11-17
    • 1970-01-01
    • 1970-01-01
    • 2021-06-25
    • 2019-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多