用于更新临时表的复杂查询。可能派生表或相关子查询?

时间:2017-08-26 05:20:07

标签: sql sql-server tsql

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

  • 如果员工目前正在休假,我将收到离职原因
  • 如果EmpSts为On Leave
  • ,员工将被视为休假
  • “离开原因”来自EmlChgRsn(就业变更原因)列,因此,如果员工休假,则此实例中的所需输出将为FMLAFull BegFMLAInt Beg
  • EmlEfdDt IS NULL是该员工最近的条目的记录。
  • 下面显示了两种不同类型的数据方案。第一张图片很简单 - 如果EmlEfdDt IS NULL and EmlSts = "On Leave" and EmlChgRsn LIKE '%FMLA%',则只显示EmlChgRsn。
  • 第二个形象是困难的部分 - 自员工休假以来,已经对就业做了一些调整,例如主管变更和工资变动。在这种情况下,我需要搜索与leave-- FMLAInt Beg相关的最新EmlChgRsn。

源数据如下所示:

enter image description here

OR

enter image description here

根据我在下面的示例数据,最终结果应如下所示: enter image description here

以下是一些示例数据,以帮助解决这个问题。关于我获取简单数据的第一步的注意事项 - 如果你做了一两次通过或做一些想要一次性更新它的事情,那就不重要了。我只需要完成:)感谢您的帮助!!

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

2 个答案:

答案 0 :(得分: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,Jason

答案 1 :(得分:0)

对于任何给定的员工,您似乎只想要最近出现的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重新开始

如果您正在努力将此更改为更改jobinfo表的更新,请告诉我......我认为您可以使用该部分,但