无法将此查询正确分组

时间:2017-01-01 23:26:28

标签: sql-server

tEmplHistory表包含员工的时间顺序记录。每条记录都有一个开始日期,指示该员工的状态何时发生变化。我需要提取最接近但未超过某个特定日期的所有员工的所有记录。每个员工的记录将是该员工在该给定日期之前的记录。在输出中我需要EmplHistoryID,这就是全部。这就是我被困的地方:

This is where I'm stuck 这是表格:

USE foo
GO

/****** Object:  Table [dbo].[tEmplHistory]    Script Date: 1/1/2017 6:12:54 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[tEmplHistory](
    [EmplHistoryID] [int] IDENTITY(1,1) NOT NULL,
    [StartDate] [datetime] NOT NULL,
    [EmplStatusID] [int] NOT NULL,
    [Comment] [nvarchar](max) NULL,
    [DateStamp] [datetime] NOT NULL,
    [EmplID] [int] NOT NULL,
 CONSTRAINT [PK_tEmplHistory] PRIMARY KEY CLUSTERED 
(
    [EmplHistoryID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

以下是一些数据:

INSERT
    [dbo].[tEmplHistory]
    ( [EmplHistoryID], [StartDate], [EmplStatusID], [Comment], [DateStamp], [EmplID] )
VALUES
    (9375, CAST(0x0000A6EE0104A007 AS DateTime), 1, NULL, CAST(0x0000A6EE0104A007 AS DateTime), 2768),
    (9376, CAST(0x0000A58000000000 AS DateTime), 1, NULL, CAST(0x0000A6EE010B2D97 AS DateTime), 2768),
    (9377, CAST(0x0000A43100000000 AS DateTime), 1, NULL, CAST(0x0000A6EE010B481D AS DateTime), 2768),
    (9378, CAST(0x0000A58100000000 AS DateTime), 1, NULL, CAST(0x0000A6EE010B591F AS DateTime), 2768),
    (9379, CAST(0x0000A57F00000000 AS DateTime), 1, NULL, CAST(0x0000A6EE010B6F5C AS DateTime), 2768),
    (9380, CAST(0x0000A57E00000000 AS DateTime), 1, NULL, CAST(0x0000A6EE010B7AB7 AS DateTime), 2768),
    (9381, CAST(0x0000A58100000000 AS DateTime), 1, NULL, CAST(0x0000A6EE010B9343 AS DateTime), 2768),
    (9382, CAST(0x0000A58200000000 AS DateTime), 2, NULL, CAST(0x0000A6EE01188D3E AS DateTime), 2767),
    (9383, CAST(0x0000A57F00000000 AS DateTime), 2, NULL, CAST(0x0000A6EE011903FF AS DateTime), 2767),
    (9384, CAST(0x0000A57E00000000 AS DateTime), 2, NULL, CAST(0x0000A6EE01194FF5 AS DateTime), 2767),
    (9385, CAST(0x0000A58100000000 AS DateTime), 1, NULL, CAST(0x0000A6EE012780A6 AS DateTime), 2),
    (9386, CAST(0x0000A58000000000 AS DateTime), 2, NULL, CAST(0x0000A6EE01278D59 AS DateTime), 2),
    (9387, CAST(0x0000A57F00000000 AS DateTime), 3, NULL, CAST(0x0000A6EE0127A45A AS DateTime), 2)

    SET IDENTITY_INSERT [dbo].[tEmplHistory] OFF
    GO

对于此示例数据,我需要三个EmplHistoryID值:

9386 for EmplID = 2
9383 for EmplID = 2767
9376 for EmplID 2768

3 个答案:

答案 0 :(得分:0)

  

我需要为最接近但未超过某个特定日期的所有员工提取所有记录。

您的问题更难以通过样本数据中的模糊日期来回答。在20年的T-SQL工作中,这是我第一次看到显式转换为datetime的二进制值。通常,文字值以字符串形式提供。

但是,查询的基本形式并不复杂。您希望在某个日期之前所有记录,而不仅仅是一个,所以

select * from tEmplHistory where StartDate <  '1/1/1990' 

或您希望指定的任何日期。

但也许这不是你的意思?也许您指的是每个员工 单行之前和最接近某个日期?为此你需要一个相关的子查询:

select * from tEmplHistory as H where exists (
    select 1 from tEmplHistory 
    where EmplHistoryID = H.EmplHistoryID
    and StartDate <  '1/1/1990' 
    group by EmplHistoryID
    having max(StartDate) = H.StartDate
)

子查询在每个EmplHistoryID的给定日期之前找到最新的开始日期。该日期和EmplHistoryID连接到外部表中的行(在本例中是相同的表)。

答案 1 :(得分:0)

对于每个员工,您希望在给定日期之前获得最新记录。因此,您在该日期之前选择记录,按日期对每位员工的记录进行排名并保留最新记录:

select emplid, emplhistoryid
from
(
  select 
    emplid, 
    emplhistoryid, 
    row_number() over(partition by emplid order by datestamp desc) as rn 
  from templhistory eh
  where datestamp <= '20161231'
) ranked
where rn = 1;

答案 2 :(得分:0)

如果我们想要在2016-01-01之前拉动其状态发生变化的员工,则以下内容将起作用。

    SELECT EMPLHISTORYID ,EMPID FROM 
(
    SELECT EMPLHISTORYID,[EmplID] AS EMPID,
    STARTDATE,RANK() OVER (PARTITION BY [EmplID] ORDER BY StarttDate   Desc )   as RNK
FROM [dbo].[tEmplHistory]
WHERE startDATE <='2016-01-01 00:00:00'
 )A
WHERE A.RNK=1