SELECT 使用 SQL Server 2008 R2 根据特定条件从下一行中选择的查询?
SELECT query that Selects from Next Row given certain criteria using SQL Server 2008 R2?
我想创建一个 table 在同一行显示员工的雇用日期和随附的任期日期。我在 2 table 秒内使用数据:employees
和 EEChange
。
EEChange
有三列很重要:employee_no
、action_date
、action_type
。对于 'Hire'、'Rehire' 或 'Term',action_type
只会是 'H'、'R' 或 'T'。就我而言,'Hire' 和 'Rehire' 日期是生效日期,'Term' 日期是终止日期。
我可以创建一个 select 查询,将生效日期 (ED) 放在 ED 列中,将期限日期 (TD) 放在 TD 列中。问题是他们不在同一行。我遇到的另一个困难是每个 ED 可能没有关联的 TD。见下文:员工 (EE) 14 于 98 年 5 月 1 日受雇,于 2006 年 9 月 13 日再次受雇,并于 98 年 3 月 23 日任期届满。我不知道为什么我的数据库有一个 Rehire,然后是一个 Hire。就我而言,EE 14 于 98 年 5 月 1 日被聘用,并于 98 年 3 月 23 日任期届满。我假设就业没有中断。
这是我的 tables:
employees
:
EE No Name
6 Anil
12 Viktor
14 Sherry
15 Juan
48 Susan
50 Kevin
EEChange
:
EE No Action_type Action_date
6 H 5/1/1998
6 T 7/26/2010
12 H 5/1/1998
12 R 4/16/2012
14 H 5/1/1998
14 R 9/13/2006
14 T 9/19/2008
15 H 3/23/1998
48 H 7/1/1998
48 R 10/21/2008
48 T 1/3/2009
50 H 7/2/1998
50 R 7/16/2010
50 T 5/1/2012
50 R 12/1/2013
50 T 2/15/2015
我的查询:
SELECT
LTRIM(employees.employee_no) as [EE No],
row_number() OVER (PARTITION BY employees.employee_no ORDER BY EEChange.action_date) AS [Seq],
EEChange.action_type,
CASE
WHEN EEChange.action_type = 'H' OR EEChange.action_type = 'R'
THEN EEChange.action_date
END AS [Effective Date],
CASE
WHEN EEChange.action_type = 'T'
THEN EEChange.action_date
END AS [Term Date]
FROM
dbo.employees employees
LEFT OUTER JOIN
dbo.emp_employment_action_changes EEchange ON employees.employee_no = EEChange.employee_no
我添加了 Sequence
列以查看是否可以为每个 [EE No]
排序 action_date
列。我能够这样做,但最终没有成功,并找到了一个 select 可以给我所需结果的查询:ED 和 TD 在同一行。
我的结果:
EE No Seq action_type Effective Date Term Date
6 1 H 5/1/1998
6 2 T 7/26/2010
12 1 H 5/1/1998
12 2 R 4/16/2012
14 1 H 5/1/1998
14 2 R 9/13/2006
14 3 T 9/19/2008
15 1 H 3/23/1998
48 1 H 7/1/1998
48 2 R 10/21/2008
48 3 T 1/3/2009
50 1 H 7/2/1998
50 2 R 7/16/2010
50 3 T 5/1/2012
50 4 R 12/1/2013
50 5 T 2/15/2015
想要的结果:
EE No Name Effective Date Term Date
6 Anil 5/1/1998 7/26/2010
12 Viktor 5/1/1998
14 Sherry 5/1/1998 9/19/2008
15 Juan 3/23/1998
48 Susan 7/1/1998 1/3/2009
50 Kevin 7/2/1998 5/1/2012
50 Kevin 12/1/2013 2/15/2015
注意 Kevin 在 EEChange
table 中有 5 行。我只想要第一个 ED 及其随附的学期日期和下一个 ED 及其随附的学期日期。对于活跃的 EE,将没有最终学期日期。
任何人都可以提供任何帮助。我尝试使用 LEAD()
但它不适用于 SQL Server 2008 R2。我找不到让 LEAD()
跳过 TD 之前序列中出现的 ED 的方法。
所以,看起来你的问题确实是一个间隙和孤岛问题,这意味着你需要找到离散范围的起点和终点。如果我们将操作 H 和 R 都视为范围开始的标记,问题将是找到每个开始日期之后的最早结束日期,该日期晚于该日期。 (有点——我觉得很难描述)。不过,逻辑应该很容易理解。
我用你的示例数据进行了测试,这个查询似乎给出了想要的结果。
with
a as (
select
e.EENo, e.Name,
case
when Action_type IN ('R','H')
then Action_date
end Effective_date,
case
when Action_type = 'T'
then Action_date
end Term_date
from employees e
join EEChange ee on e.EENo = ee.EENo
),
b as (
select
EENo, Name, Effective_date,
case
when Effective_date is not null
then (
select min(term_date)
from a a2
where a2.Term_date > a.Effective_date and a2.EENo = a.EENo
)
end Term_date
from a
)
select
EENo, Name, min(Effective_date) Effective_date, Term_date
from b
where Effective_date is not null
group by EENo, Name, Term_date
示例结果:
| EENo | Name | Effective_date | Term_date |
|------|--------|----------------|------------|
| 6 | Anil | 1998-05-01 | 2010-07-26 |
| 12 | Viktor | 1998-05-01 | (null) |
| 14 | Sherry | 1998-05-01 | 2008-09-19 |
| 15 | Juan | 1998-03-23 | (null) |
| 48 | Susan | 1998-07-01 | 2009-01-03 |
| 50 | Kevin | 1998-07-02 | 2012-05-01 |
| 50 | Kevin | 2013-12-01 | 2015-02-15 |
declare @employees table (EE int, Name varchar(20));
insert @employees values
(6,'Anil'),
(12,'Viktor'),
(14,'Sherry'),
(15,'Juan'),
(48,'Susan'),
(50,'Kevin');
declare @EEChange table (EENo int, Action_type char, Action_date date);
insert @EEChange values
(6,'H','5/1/1998'),
(6,'T','7/26/2010'),
(12,'H','5/1/1998'),
(12,'R','4/16/2012'),
(14,'H','5/1/1998'),
(14,'R','9/13/2006'),
(14,'T','9/19/2008'),
(15,'H','3/23/1998'),
(48,'H','7/1/1998'),
(48,'R','10/21/2008'),
(48,'T','1/3/2009'),
(50,'H','7/2/1998'),
(50,'R','7/16/2010'),
(50,'T','5/1/2012'),
(50,'R','12/1/2013'),
(50,'T','2/15/2015');
;with CTE AS (
SELECT
LTRIM(employees.EE) as [EE No],employees.Name,
row_number() OVER (PARTITION BY employees.EE ORDER BY EEChange.action_date) AS [Seq],
EEChange.action_type,
CASE WHEN EEChange.action_type = 'H' OR EEChange.action_type = 'R' THEN
EEChange.action_date
END AS [Effective Date],
CASE WHEN EEChange.action_type = 'T' THEN
EEChange.action_date
END AS [Term Date]
FROM @employees employees
LEFT OUTER JOIN @EEChange EEchange ON employees.EE = EEChange.EEno
)
select [EE No],Name,MIN([Effective Date])[Effective Date],MIN([Term Date])[Term Date] from CTE
GROUP BY [EE No],Name
UNION
select [EE No],Name,MAX([Effective Date])[Effective Date],MAX([Term Date])[Term Date] from CTE
where Seq > 3
group by [EE No],Name
我想创建一个 table 在同一行显示员工的雇用日期和随附的任期日期。我在 2 table 秒内使用数据:employees
和 EEChange
。
EEChange
有三列很重要:employee_no
、action_date
、action_type
。对于 'Hire'、'Rehire' 或 'Term',action_type
只会是 'H'、'R' 或 'T'。就我而言,'Hire' 和 'Rehire' 日期是生效日期,'Term' 日期是终止日期。
我可以创建一个 select 查询,将生效日期 (ED) 放在 ED 列中,将期限日期 (TD) 放在 TD 列中。问题是他们不在同一行。我遇到的另一个困难是每个 ED 可能没有关联的 TD。见下文:员工 (EE) 14 于 98 年 5 月 1 日受雇,于 2006 年 9 月 13 日再次受雇,并于 98 年 3 月 23 日任期届满。我不知道为什么我的数据库有一个 Rehire,然后是一个 Hire。就我而言,EE 14 于 98 年 5 月 1 日被聘用,并于 98 年 3 月 23 日任期届满。我假设就业没有中断。
这是我的 tables:
employees
:
EE No Name
6 Anil
12 Viktor
14 Sherry
15 Juan
48 Susan
50 Kevin
EEChange
:
EE No Action_type Action_date
6 H 5/1/1998
6 T 7/26/2010
12 H 5/1/1998
12 R 4/16/2012
14 H 5/1/1998
14 R 9/13/2006
14 T 9/19/2008
15 H 3/23/1998
48 H 7/1/1998
48 R 10/21/2008
48 T 1/3/2009
50 H 7/2/1998
50 R 7/16/2010
50 T 5/1/2012
50 R 12/1/2013
50 T 2/15/2015
我的查询:
SELECT
LTRIM(employees.employee_no) as [EE No],
row_number() OVER (PARTITION BY employees.employee_no ORDER BY EEChange.action_date) AS [Seq],
EEChange.action_type,
CASE
WHEN EEChange.action_type = 'H' OR EEChange.action_type = 'R'
THEN EEChange.action_date
END AS [Effective Date],
CASE
WHEN EEChange.action_type = 'T'
THEN EEChange.action_date
END AS [Term Date]
FROM
dbo.employees employees
LEFT OUTER JOIN
dbo.emp_employment_action_changes EEchange ON employees.employee_no = EEChange.employee_no
我添加了 Sequence
列以查看是否可以为每个 [EE No]
排序 action_date
列。我能够这样做,但最终没有成功,并找到了一个 select 可以给我所需结果的查询:ED 和 TD 在同一行。
我的结果:
EE No Seq action_type Effective Date Term Date
6 1 H 5/1/1998
6 2 T 7/26/2010
12 1 H 5/1/1998
12 2 R 4/16/2012
14 1 H 5/1/1998
14 2 R 9/13/2006
14 3 T 9/19/2008
15 1 H 3/23/1998
48 1 H 7/1/1998
48 2 R 10/21/2008
48 3 T 1/3/2009
50 1 H 7/2/1998
50 2 R 7/16/2010
50 3 T 5/1/2012
50 4 R 12/1/2013
50 5 T 2/15/2015
想要的结果:
EE No Name Effective Date Term Date
6 Anil 5/1/1998 7/26/2010
12 Viktor 5/1/1998
14 Sherry 5/1/1998 9/19/2008
15 Juan 3/23/1998
48 Susan 7/1/1998 1/3/2009
50 Kevin 7/2/1998 5/1/2012
50 Kevin 12/1/2013 2/15/2015
注意 Kevin 在 EEChange
table 中有 5 行。我只想要第一个 ED 及其随附的学期日期和下一个 ED 及其随附的学期日期。对于活跃的 EE,将没有最终学期日期。
任何人都可以提供任何帮助。我尝试使用 LEAD()
但它不适用于 SQL Server 2008 R2。我找不到让 LEAD()
跳过 TD 之前序列中出现的 ED 的方法。
所以,看起来你的问题确实是一个间隙和孤岛问题,这意味着你需要找到离散范围的起点和终点。如果我们将操作 H 和 R 都视为范围开始的标记,问题将是找到每个开始日期之后的最早结束日期,该日期晚于该日期。 (有点——我觉得很难描述)。不过,逻辑应该很容易理解。
我用你的示例数据进行了测试,这个查询似乎给出了想要的结果。
with
a as (
select
e.EENo, e.Name,
case
when Action_type IN ('R','H')
then Action_date
end Effective_date,
case
when Action_type = 'T'
then Action_date
end Term_date
from employees e
join EEChange ee on e.EENo = ee.EENo
),
b as (
select
EENo, Name, Effective_date,
case
when Effective_date is not null
then (
select min(term_date)
from a a2
where a2.Term_date > a.Effective_date and a2.EENo = a.EENo
)
end Term_date
from a
)
select
EENo, Name, min(Effective_date) Effective_date, Term_date
from b
where Effective_date is not null
group by EENo, Name, Term_date
示例结果:
| EENo | Name | Effective_date | Term_date |
|------|--------|----------------|------------|
| 6 | Anil | 1998-05-01 | 2010-07-26 |
| 12 | Viktor | 1998-05-01 | (null) |
| 14 | Sherry | 1998-05-01 | 2008-09-19 |
| 15 | Juan | 1998-03-23 | (null) |
| 48 | Susan | 1998-07-01 | 2009-01-03 |
| 50 | Kevin | 1998-07-02 | 2012-05-01 |
| 50 | Kevin | 2013-12-01 | 2015-02-15 |
declare @employees table (EE int, Name varchar(20));
insert @employees values
(6,'Anil'),
(12,'Viktor'),
(14,'Sherry'),
(15,'Juan'),
(48,'Susan'),
(50,'Kevin');
declare @EEChange table (EENo int, Action_type char, Action_date date);
insert @EEChange values
(6,'H','5/1/1998'),
(6,'T','7/26/2010'),
(12,'H','5/1/1998'),
(12,'R','4/16/2012'),
(14,'H','5/1/1998'),
(14,'R','9/13/2006'),
(14,'T','9/19/2008'),
(15,'H','3/23/1998'),
(48,'H','7/1/1998'),
(48,'R','10/21/2008'),
(48,'T','1/3/2009'),
(50,'H','7/2/1998'),
(50,'R','7/16/2010'),
(50,'T','5/1/2012'),
(50,'R','12/1/2013'),
(50,'T','2/15/2015');
;with CTE AS (
SELECT
LTRIM(employees.EE) as [EE No],employees.Name,
row_number() OVER (PARTITION BY employees.EE ORDER BY EEChange.action_date) AS [Seq],
EEChange.action_type,
CASE WHEN EEChange.action_type = 'H' OR EEChange.action_type = 'R' THEN
EEChange.action_date
END AS [Effective Date],
CASE WHEN EEChange.action_type = 'T' THEN
EEChange.action_date
END AS [Term Date]
FROM @employees employees
LEFT OUTER JOIN @EEChange EEchange ON employees.EE = EEChange.EEno
)
select [EE No],Name,MIN([Effective Date])[Effective Date],MIN([Term Date])[Term Date] from CTE
GROUP BY [EE No],Name
UNION
select [EE No],Name,MAX([Effective Date])[Effective Date],MAX([Term Date])[Term Date] from CTE
where Seq > 3
group by [EE No],Name