2017-06-20 5 views
4

私はこれを理解しようとしているサークルで回っています。SQL - 最新の契約を終了したが他の契約を開いている従業員を選択

最新の契約を終了したが、有効な契約が以前から開いている従業員を選択しようとしています。

たとえば、従業員はいくつかの契約を持っています(一部は一時的でもパートタイムでもかまいませんが、これは無関係ですが最新の契約を終了しますが、引き続き古い契約をしています)。

私が達成しようとしているものにとして下記の表を参照してください - 関連分野で:

:ここ

+------+-------------+-------------+------------+------------+ 
| ID | CONTRACT_ID | EMPLOYEE_ID | START_DATE | END_DATE | 
+------+-------------+-------------+------------+------------+ 
| 4321 | 974   | 321   | 21/01/2004 | 31/12/2016 | 
+------+-------------+-------------+------------+------------+ 
| 4322 | 1485  | 321   | 09/01/2009 | 31/08/2014 | 
+------+-------------+-------------+------------+------------+ 
| 4323 | NULL  | 321   | 25/07/2009 | 31/01/2010 | 
+------+-------------+-------------+------------+------------+ 
| 4324 | 2440  | 321   | 01/06/2012 | NULL  | 
+------+-------------+-------------+------------+------------+ 
| 4325 | 7368  | 321   | 01/01/2017 | NULL  | 
+------+-------------+-------------+------------+------------+ 
| 4326 | 7612  | 321   | 14/02/2017 | 06/06/2017 | 
+------+-------------+-------------+------------+------------+ 

は、正しいデータを戻すされていない私は現在持っているコードであり、

select 
cond.EMPLOYEE_ID 
,cond.END_DATE 

from 
contracts as cond 

join 
(select 

EMPLOYEE_ID 
,START_DATE 
,END_DATE 

from 
contracts 

where 
END_DATE is null) a on a.EMPLOYEE_ID = cond.employee_id and a.START_DATE <  
cond.END_DATE 

group by cond.end_date, cond.EMPLOYEE_ID 

having 
max(cond.START_DATE) is not null AND cond.END_DATE is not null 

これは(例)で何をコードした結果である:

+------+-------------+-------------+------------+------------+ 
| ID | CONTRACT_ID | EMPLOYEE_ID | START_DATE | END_DATE | 
+------+-------------+-------------+------------+------------+ 
| 1234 | NULL  | 123   | 03/12/2014 | 26/10/2015 | 
+------+-------------+-------------+------------+------------+ 
| 1235 | NULL  | 123   | 30/10/2015 | 28/01/2016 | 
+------+-------------+-------------+------------+------------+ 
| 1236 | NULL  | 123   | 06/11/2015 | 28/01/2016 | 
+------+-------------+-------------+------------+------------+ 
| 1237 | 1234  | 123   | 07/03/2016 | NULL  | 
+------+-------------+-------------+------------+------------+ 
| 1238 | NULL  | 123   | 04/04/2017 | 13/04/2017 | 
+------+-------------+-------------+------------+------------+ 
| 1239 | NULL  | 123   | 18/04/2017 | NULL  | 
+------+-------------+-------------+------------+------------+ 

あなたは、メートルを見ることができるように最近の契約には終了日がありませんが、オープン契約があります。

ご迷惑をおかけして申し訳ございません。

+0

申し訳ありません、これを投稿に追加していません。SQL Server 2012 –

+0

期待どおりの結果を投稿することはできますか? –

+0

期待される結果については、最初の表を参照してください。 –

答えて

1

start_dateend_date最新の、そしてopen_contractsのカウントは、ウィンドウ集約関数count()over()を使用して取得する

create table contracts (id int, contract_id int, employee_id int, start_date date, end_date date); 
insert into contracts values 
(4321, 974, 321, '20040121', '20161231') 
,(4322, 1485, 321, '20090109', '20140831') 
,(4323, null, 321, '20090725', '20100131') 
,(4324, 2440, 321, '20120601', null) 
,(4325, 7368, 321, '20170101', null) 
,(4326, 7612, 321, '20170214', '20170606') 
,(1, 1, 1, '20160101', null) 
,(2, 2, 1, '20160701', '20161231') 
,(3, 3, 1, '20170101', null)  /* most recent is open, do not return */ 
,(4, 4, 2, '20160101', '20170630') 
,(5, 5, 2, '20160701', '20161231') 
,(6, 6, 2, '20170101', '20170630') /* most recent is closed, no others open, do not return */ 
,(7, 7, 3, '20160101', '20170630') 
,(8, 8, 3, '20160701', null) 
,(9, 9, 3, '20170101', '20170630') /* most recent is closed, one other open, return */ 
; 

rextesterデモ:http://rextester.com/BUYKJ77928

リターン:

+------+-------------+-------------+------------+------------+----------------+--------------+----------------+ 
| id | contract_id | employee_id | start_date | end_date | max_start_date | max_end_date | open_contracts | 
+------+-------------+-------------+------------+------------+----------------+--------------+----------------+ 
| 7 | 7   |   3 | 2016-01-01 | 2017-06-30 | 2017-01-01  | 2017-06-30 |    1 | 
| 8 | 8   |   3 | 2016-07-01 | NULL  | 2017-01-01  | 2017-06-30 |    1 | 
| 9 | 9   |   3 | 2017-01-01 | 2017-06-30 | 2017-01-01  | 2017-06-30 |    1 | 
| 4321 | 974   |   321 | 2004-01-21 | 2016-12-31 | 2017-02-14  | 2017-06-06 |    2 | 
| 4322 | 1485  |   321 | 2009-01-09 | 2014-08-31 | 2017-02-14  | 2017-06-06 |    2 | 
| 4323 | NULL  |   321 | 2009-07-25 | 2010-01-31 | 2017-02-14  | 2017-06-06 |    2 | 
| 4324 | 2440  |   321 | 2012-06-01 | NULL  | 2017-02-14  | 2017-06-06 |    2 | 
| 4325 | 7368  |   321 | 2017-01-01 | NULL  | 2017-02-14  | 2017-06-06 |    2 | 
| 4326 | 7612  |   321 | 2017-02-14 | 2017-06-06 | 2017-02-14  | 2017-06-06 |    2 | 
+------+-------------+-------------+------------+------------+----------------+--------------+----------------+ 
+0

これはすべてを拾う最良の解決策です。提供された他のソリューションのいくつかは、同じ日付から始まる複数の契約を考慮していませんでした(ここではかなり多く発生しています)。どうもありがとう! –

1

私は、SQLサーバーの専門家ではないんだけど、あなたはこれに似たもの試してみてください:

SELECT * 
FROM contracts cont 
WHERE cont.end_date IS NOT NULL 
    AND cont.end_date <= SYSDATE 
    AND NOT EXISTS (SELECT * 
        FROM contracts recent 
        WHERE recent.employee_id = cont.employee_id 
        AND recent.start_date > cont.start_date) 
    AND EXISTS (SELECT * 
       FROM contracts openc 
       WHERE openc.employee_id = cont.employee_id 
       AND (openc.end_date IS NULL OR openc.end_date > SYSDATE)) 

閉じ契約のための最初の2つの条件検索を。
次のもの(「存在しない」)は、選択した契約が最新のものであることを確認します。
最後の部分は、他の未定義契約があることを保証します。

+0

このソリューションをお寄せいただきありがとうございます。しかし、他のソリューションから得られた結果(正しい)が返ってくるようには戻っていないようです。私は、それが同じ日に始まる複数の契約と関係していると思います。 –

0

あなたはROW_NUMBER()でこれを行うことができますし、CTE

は、アクションでそれを参照してください:以下のコードで

http://rextester.com/HQVXF56741は、私はあなたがしなければならないかもしれないDATEFORMATを変更しました。いくつかの追加の例で

select 
    c.id 
    , c.contract_id 
    , c.employee_id 
    , start_date  
    , end_date  
    , max_start_date = x.start_date 
    , max_end_date = x.end_date 
    , x.open_contracts 
from contracts c 
    cross apply (
    select top 1 
     i.start_date 
     , i.end_date 
     , open_contracts = count(case when i.end_date is null then 1 end) over(partition by i.employee_id) 
    from contracts i 
    where i.employee_id = c.employee_id 
    order by i.start_date desc 
    ) x 
where x.end_date is not null 
    and x.open_contracts > 0 
order by c.employee_id, c.start_date asc 

テストのセットアップ:cross apply()を使用して

set dateformat dmy 
declare @table table (ID int,CONTRACT_ID int, EMPLOYEE_ID int, [START_DATE] datetime, END_DATE datetime) 
insert into @table 
values 
(4321,974,321,'21/01/2004','31/12/2016'), 
(4322,1485,321,'09/01/2009','31/08/2014'), 
(4323,NULL,321,'25/07/2009','31/01/2010'), 
(4324,2440,321,'01/06/2012',NULL), 
(4325,7368,321,'01/01/2017',NULL), 
(4326,7612,321,'14/02/2017','06/06/2017') 

--this applies a row_number to each contract per employee 
--the most recent contract (by start date) gets a 1 
;with cte as(
    select 
     EMPLOYEE_ID 
     ,ID 
     ,row_number() over (partition by EMPLOYEE_ID order by [START_DATE] desc) as ContractRecentcy 
    from @table) 


--this will return all contacts that are open, which aren't the most recent for the employee. 
select 
    t.* 
from 
    @table t 
where 
    t.END_DATE is null 
    and t.ID not in (select ID from cte where ContractRecentcy = 1) 

set dateformat mdy 
1

はこの男を試してみてください。

SELECT [EMPLOYEE_ID] 

FROM [contracts] 

WHERE [END_DATE] IS NULL 

AND [EMPLOYEE_ID] IN (SELECT B.[EMPLOYEE_ID] FROM (
SELECT * FROM (
SELECT RowN = Row_Number() over (partition by [EMPLOYEE_ID] ORDER BY[START_DATE] DESC) 
, [EMPLOYEE_ID] 
, [CONTRACT_ID] 
, [END_DATE] 

FROM [contracts] 

) A 
WHERE A.[END_DATE] IS NOT NULL 
AND A.[RowN] = 1) B) 
+0

素晴らしいソリューションですありがとうございました。 –

+0

*更新*複製のために別個に追加しました。 –

+0

*更新2 *これは、同じ日に開始する複数の契約を持つ従業員がいないようです。 –

関連する問題