2017-02-16 7 views
-1

У меня есть таблица, подобная этой.Выберите последовательные идентификаторы в SQL Server 2012

ID    Installment ID  DateDue 
------------------------------------------------------------  
000000000008 29     2017-03-15 00:00:00.000 
000000000008 30     2017-04-15 00:00:00.000 
000000000008 32     2017-06-15 00:00:00.000 
000000000008 33     2017-07-15 00:00:00.000 
000000000008 34     2017-08-15 00:00:00.000 

Что мне нужно, это выбрать запрос, который возвращает данные только 3 успешных последовательных взносов (поэтому в данном примере 32,33,34), между определенным диапазоном дат.

Предполагаемые неудачи заполняются другой таблицей (31).

Так что я хотел бы вернуть серийный номер, идентификатор платежа.

+0

6,6,7 - Последовательный? – DarkKnight

+0

Извините, исправлено. 6,7,8 –

+0

, что он должен вернуть, если у вас есть 3,4,6,7,8,9? – DarkKnight

ответ

0

Вы можете использовать функции LEAD и LAG, доступные в SqlServer 2012, и выполните следующие действия.

Demo here

;WITH cte1 AS 
(
SELECT * , datepart(m,(lead(datedue) OVER(ORDER BY installmentid)))-DATEPART(m,datedue) nowtonext 
     ,DATEPART(m,datedue)-datepart(m,(lag(datedue) OVER(ORDER BY installmentid))) prevtonow 
     ,ROW_NUMBER() OVER(ORDER BY installmentid) as rn 
FROM YourTable 
), 
cte2 AS 
(
SELECT rn,id,installmentid,datedue,nowtonext,prevtonow 
     ,lead(prevtonow) OVER(ORDER BY rn) AS prev 
     ,lag(nowtonext) OVER(ORDER BY rn) AS nxt 
FROM cte1 
) 

SELECT id,installmentid,datedue 
FROM cte1 
WHERE rn BETWEEN (SELECT rn-1 FROM cte2 WHERE nowtonext = 1 AND prevtonow=1 AND prev=1 AND nxt=1) 
      and (SELECT rn+1 FROM cte2 WHERE nowtonext = 1 AND prevtonow=1 AND prev=1 AND nxt=1) 
0

Вы можете использовать следующий запрос, чтобы вернуть острова последовательных записей, имеющих последовательные InstallmentID номера:

;WITH CTE_Group AS (
    SELECT ID, 
      InstallmentID, 
      DateDue, 
      ROW_NUMBER() OVER (PARTITION BY ID 
          ORDER BY DateDue) - InstallmentID AS grp 
    FROM mytable 
    WHERE DateDue BETWEEN @startDate AND @endDate 
), CTE_Count AS (
    SELECT ID, InstallmentID, DateDue, 
      COUNT(*) OVER (PARTITION BY ID, grp) AS cnt 
    FROM CTE_Group 
) 
SELECT ID, InstallmentID, DateDue 
FROM CTE_Count 
WHERE cnt >= 3 

Если вы хотите только три записи из каждого острова, а затем вы можете использовать ROW_NUMBER с предложением PARTITION BY cnt, чтобы извлечь первые 3 записи острова.

Объяснение: Запрос первого КТР, CTE_Group, использует «разницу между номерами строк трюком» с целью выявления последовательных записей, имеющих последовательные номера InstallmentID в пределах заранее определенного диапазона дат (@startDate - @endDate).

Выход из CTE_Group:

ID InstallmentID DateDue  grp 
------------------------------------ 
8 29    2017-03-15 -28 
8 30    2017-04-15 -28 
8 32    2017-06-15 -29 
8 33    2017-07-15 -29 
8 34    2017-08-15 -29 

Запрос второго КТР, CTE_Count, использует COUNT() OVER() для подсчета населения каждого острова.

Выход из CTE_Count:

ID InstallmentID DateDue  Cnt 
----------------------------------- 
8 32    2017-06-15 3 
8 33    2017-07-15 3 
8 34    2017-08-15 3 
8 29    2017-03-15 2 
8 30    2017-04-15 2 

CTE_Count Использование можно легко отфильтровать записи, которые принадлежат острова с населением 2 или меньше.

Demo here