【问题标题】:Complex query to update a temp table. Possibly derived table or correlated sub query?用于更新临时表的复杂查询。可能是派生表或相关子查询?
【发布时间】:2017-08-26 05:20:06
【问题描述】:

我有一个疑问,我很难理解。我需要根据以下条件更新临时表中的字段:

  • 如果员工目前正在休假,我将获得休假原因
  • 如果 EmpSts 为 On Leave,则认为员工休假
  • 请假原因来自 EmlChgRsn(就业变更原因)列,因此,如果员工请假,则在本例中,所需的输出将是 FMLAFull BegFMLAInt Beg
  • EmlEfdDt IS NULL 是该员工的最新条目的记录。
  • 下面显示了两种不同类型的数据场景。第一张图片很简单——如果是EmlEfdDt IS NULL and EmlSts = "On Leave" and EmlChgRsn LIKE '%FMLA%',则只显示EmlChgRsn。
  • 第二张图是最难的部分——员工休假后对就业进行了一些调整,例如主管变动和工资变动。我需要搜索与请假相关的最新 EmlChgRsn——在这种情况下为 FMLAInt Beg

源数据如下所示:

根据我下面的示例数据,最终结果应如下所示:

以下是一些示例数据,可帮助您弄清楚这一点。请注意我在获取简单数据时的第一次传递——如果你做一两次传递或做一些花哨的事情来一次更新它,这并不重要。我只需要完成 :) 谢谢你的帮助!!

--Create temp table to update
CREATE TABLE #JobInfo (
 Emp varchar(10) NULL
,LeaveReason varchar(50) NULL
);
--Insert primer record with emp id's
INSERT INTO #JobInfo 
VALUES (3750, '')
  ,(3752, '')

--Create source data table
CREATE TABLE #Employment (
   Eml varchar(1) NULL
  ,EmlChgRsn varchar(50) NULL
  ,EmlEfdDt varchar(10) NULL
  ,Emp varchar(10) NULL
  ,EmpSts varchar(50) NULL
);

--Populate source data table with mock data
INSERT INTO #Employment
VALUES ('1', 'FMLAFull Beg', CONVERT(VARCHAR(10), DATEADD(MONTH, -6, GETDATE()), 101), '3752', 'On Leave')
  ,('1', 'Salary', CONVERT(VARCHAR(10), DATEADD(MONTH, -5, GETDATE()), 101), '3752', 'On Leave')
  ,('1', 'TeamChange', CONVERT(VARCHAR(10), DATEADD(MONTH, -4, GETDATE()), 101), '3752', 'On Leave')
  ,('1', 'Salary', CONVERT(VARCHAR(10), DATEADD(MONTH, -3, GETDATE()), 101), '3752', 'On Leave')
  ,('1', 'FMLAInt Beg', NULL, '3752', 'On Leave')
  ,('1', 'Salary', CONVERT(VARCHAR(10), DATEADD(MONTH, -7, GETDATE()), 101), '3750', 'Active')
  ,('1', 'FMLAFull Beg', CONVERT(VARCHAR(10), DATEADD(MONTH, -6, GETDATE()), 101), '3750', 'On Leave')
  ,('1', 'Salary', CONVERT(VARCHAR(10), DATEADD(MONTH, -5, GETDATE()), 101), '3750', 'On Leave')
  ,('1', 'New Supervisor', CONVERT(VARCHAR(10), DATEADD(MONTH, -4, GETDATE()), 101), '3750', 'On Leave')
  ,('1', 'FMLAInt Beg', CONVERT(VARCHAR(10), DATEADD(MONTH, -3, GETDATE()), 101), '3750', 'On Leave')
  ,('1', 'New Supervisor', NULL, '3750', 'On Leave')

-- **First pass as updating the easy records
UPDATE #JobInfo
SET LeaveReason = (SELECT CASE WHEN (EmlChgRsn LIKE '%FMLA%Beg%' OR EmlChgRsn LIKE '%Leave%Beg%')
                            AND EmpSts = 'On Leave' THEN EmlChgRsn

                          ELSE '' END
                  FROM #Employment
                  WHERE #Employment.Emp = #JobInfo.Emp 
                    AND EmlEfdDt IS NULL
                    AND Eml = 1)

SELECT *
FROM #JobInfo                   
DROP TABLE #JobInfo
DROP TABLE #Employment

【问题讨论】:

    标签: sql sql-server tsql


    【解决方案1】:

    这应该是你所追求的......

    IF OBJECT_ID('tempdb..#JobInfo', 'U') IS NOT NULL 
    DROP TABLE #JobInfo;
    
    CREATE TABLE #JobInfo (
         Emp varchar(10) NULL
        ,LeaveReason varchar(50) NULL
        );
    --Insert primer record with emp id's
    INSERT INTO #JobInfo VALUES (3750, ''), (3752, '');
    
    IF OBJECT_ID('tempdb..#Employment', 'U') IS NOT NULL 
    DROP TABLE #Employment;
    
    CREATE TABLE #Employment (
       Eml varchar(1) NULL
      ,EmlChgRsn varchar(50) NULL
      ,EmlEfdDt varchar(10) NULL
      ,Emp varchar(10) NULL
      ,EmpSts varchar(50) NULL
        );
    
    --Populate source data table with mock data
    INSERT INTO #Employment
    VALUES ('1', 'FMLAFull Beg', CONVERT(VARCHAR(10), DATEADD(MONTH, -6, GETDATE()), 101), '3752', 'On Leave')
      ,('1', 'Salary', CONVERT(VARCHAR(10), DATEADD(MONTH, -5, GETDATE()), 101), '3752', 'On Leave')
      ,('1', 'TeamChange', CONVERT(VARCHAR(10), DATEADD(MONTH, -4, GETDATE()), 101), '3752', 'On Leave')
      ,('1', 'Salary', CONVERT(VARCHAR(10), DATEADD(MONTH, -3, GETDATE()), 101), '3752', 'On Leave')
      ,('1', 'FMLAInt Beg', NULL, '3752', 'On Leave')
      ,('1', 'Salary', CONVERT(VARCHAR(10), DATEADD(MONTH, -7, GETDATE()), 101), '3750', 'Active')
      ,('1', 'FMLAFull Beg', CONVERT(VARCHAR(10), DATEADD(MONTH, -6, GETDATE()), 101), '3750', 'On Leave')
      ,('1', 'Salary', CONVERT(VARCHAR(10), DATEADD(MONTH, -5, GETDATE()), 101), '3750', 'On Leave')
      ,('1', 'New Supervisor', CONVERT(VARCHAR(10), DATEADD(MONTH, -4, GETDATE()), 101), '3750', 'On Leave')
      ,('1', 'FMLAInt Beg', CONVERT(VARCHAR(10), DATEADD(MONTH, -3, GETDATE()), 101), '3750', 'On Leave')
      ,('1', 'New Supervisor', NULL, '3750', 'On Leave');
    
    --==============================================================================================
    
    -- solution...
    UPDATE ji SET 
        ji.LeaveReason = x.LeaveReason
    FROM
        #JobInfo ji
        JOIN #Employment e1
            ON ji.Emp = e1.Emp
        CROSS APPLY ( VALUES (CASE 
                                    WHEN e1.EmlChgRsn LIKE 'FMLA%' 
                                    THEN e1.EmlChgRsn
                                    ELSE (
                                            SELECT TOP 1 
                                                e2.EmlChgRsn
                                            FROM 
                                                #Employment e2
                                            WHERE 
                                                e1.Emp = e2.Emp
                                                AND e2.EmlChgRsn LIKE 'FMLA%'
                                            ORDER BY 
                                                e2.EmlEfdDt DESC
                                            )
                            END) ) x (LeaveReason)
    WHERE 
        e1.EmlEfdDt IS NULL
        AND e1.EmpSts = 'On Leave';
    
    SELECT * FROM #JobInfo ji;
    

    HTH,杰森

    【讨论】:

    • 我看到这给出了所需的输出。我太累了,无法将它分开以确保它是我需要的,但我明天早上会做这个,如果它检查出来,我会接受。谢谢杰森!
    【解决方案2】:

    您似乎只想要任何给定员工最近出现的 fmlafull 或 fmlaint?

    SELECT a.Eml, a.EmlChgRsn as LeaveReason FROM (
    
      SELECT
        t.*,
        ROW_NUMBER() OVER(PARTITION BY eml ORDER BY COALESCE(EmlEfdDt, GetDate()) DESC) as rown 
      FROM
        employment t
        INNER JOIN
        (SELECT eml FROM employment WHERE EmlEfdDt IS NULL and EmpSts = 'On Leave') a
        ON
          t.eml = a.eml
      WHERE
        EmlChgRsn IN ('FMLAFull Beg', 'FMLAInt Beg')
    ) a
    WHERE
      a.rown = 1
    

    我们只选择 fmla full 或 fmla int 行,我们按日期的降序排列它们,给任何 null 一个现在的日期,因为它肯定会在以后(如果不是,将查询更改为 100 年到现在)。我们将行编号为第 1 行中最近的行,然后将其全部包装在一个查询中,该查询仅选择编号为 1 的行。分区就像 groupby,对于每个唯一的 eml id,行编号从 1 重新开始

    如果您正在努力将其转变为更新以更改 jobinfo 表,请告诉我...不过我认为您会很好地处理该部分

    【讨论】:

    • 我可能读错了(这里是凌晨 2:00),但我的印象是,对于给定的 emp (EmlEfdDt IS NULL),最重传的行必须有 EmpSts = 'On Leave'.. . 所以这不仅仅是找到最reent EmlChgRsn IN ('FMLAFull Beg', 'FMLAInt Beg')的问题
    • 正确。如果最近一行的 EmpSts 为 'On Leave' ,那么他们目前正在休假。如果不是,那我现在不在乎那个雇员。
    • 我添加了一个内部联接来限制查询只查看当前休假的员工
    • 太棒了,感谢您的意见,Caius!我明天会检查一下。现在太累了:)
    • 我实际上无法让它工作。不少错误。
    猜你喜欢
    • 1970-01-01
    • 2012-08-06
    • 1970-01-01
    • 2012-10-24
    • 1970-01-01
    • 2020-08-05
    • 1970-01-01
    • 1970-01-01
    • 2013-02-27
    相关资源
    最近更新 更多