2016-02-28 4 views
-1

У меня есть эта таблица:SQL итерация для каждой группы

|ID| GruopID | Status | Date  | 
| 2| 1  | S1  | 7/29/2011 | 
| 3| 1  | S2  | 7/30/2011 | 
| 9| 1  | S1  | 8/02/2011 | 
| 7| 1  | S1  | 8/03/2011 | 
| 8| 1  | S1  | 8/04/2011 | 
| 1| 2  | S1  | 7/28/2011 | 
| 4| 2  | S2  | 7/30/2011 | 
| 5| 2  | S3  | 8/01/2011 | 
| 6| 3  | S1  | 8/02/2011 | 

, а также конкретная дата от внешнего источника: 7/31/2011

Мне нужна запрос, который даст мне для каждого GroupIDближайший верхний и нижний дата, так что результат будет:

|ID| GruopID | Status | Date  | 
| 3| 1  | S2  | 7/30/2011 | 
| 9| 1  | S1  | 8/02/2011 | 
| 4| 2  | S2  | 7/30/2011 | 
| 5| 2  | S3  | 8/01/2011 | 
| 6| 3  | S1  | 8/02/2011 | 

Может кто-то пожалуйста, помогите я и покажу мне запрос?

+0

Я использую SQL Server. И сопоставить внешнюю дату источника: 7/31/2011 –

ответ

1

прямолинейный подход:

SELECT t1.ID, t1.GroupID, t1.Status, t1.Date 
FROM MyTable t1 
WHERE t1.Date IN (
    SELECT MAX(t2.Date) 
    FROM MyTable t2 
    WHERE t2.GroupID = t1.GroupID 
    AND t2.Date <= '7/31/2011' 
    UNION 
    SELECT MIN(t3.Date) 
    FROM MyTable t3 
    WHERE t3.GroupID = t1.GroupID 
    AND t3.Date >= '7/31/2011' 
) 

Пожалуйста, обратите внимание, что количество строк в каждой группе не всегда может быть два.

  • Если есть запись с точно указанной датой 7/31/2011, то для этой группы будет возвращена одна запись.
  • Если все записи группы находятся до или после 7/31/2011, то для этой группы будет возвращена одна запись.
  • Если таблица содержит повторяющиеся комбинации GroupID и Date, тогда может быть возвращено более двух строк. Это связано с тем, что не был выбран «правильный» способ выбора между дубликатами.
+0

Этот метод может дать неверный результат, если даты не уникальны для каждой группы. –

+0

@VladimirBaranov Спасибо, я добавил это и еще несколько соображений на мой ответ. Поскольку ОП никогда не упоминал, как обращаться с дубликатами, невозможно определить, является ли текущее поведение «неправильным». –

+0

Вы правы, мне очень жаль. Я не должен был говорить «неправильно».Я имел в виду несколько строк на 'GroupID' и' Date', если есть дубликаты. –

1

Это классический запрос greatest-n-per-group. Я бы использовал CROSS APPLY здесь.

Удостоверьтесь, что у вас есть индекс на (GroupID, dt, ID).

Возможно, у вас есть таблица Groups, которая имеет список всех GroupIDs. В нижеприведенном запросе я использую CTE для получения списка всех отличных GroupIDs.

Выборочные данные

Я добавил несколько строк, чтобы показать, как запрос работает в различных случаях.

DECLARE @VarDate date = '2011-07-31'; 
DECLARE @T TABLE (ID int, GroupID int, Status varchar(2), dt date); 
INSERT INTO @T (ID, GroupID, Status, dt) VALUES 
(2, 1, 'S1', '2011-07-29'), 
(3, 1, 'S2', '2011-07-30'), 
(9, 1, 'S1', '2011-08-02'), 
(7, 1, 'S1', '2011-08-03'), 
(8, 1, 'S1', '2011-08-04'), 
(1, 2, 'S1', '2011-07-28'), 
(4, 2, 'S2', '2011-07-30'), 
(5, 2, 'S3', '2011-08-01'), 
(6, 3, 'S1', '2011-08-02'), 

(11, 4, 'S1', '2011-08-04'), 
(12, 4, 'S2', '2011-08-02'), 
(13, 4, 'S3', '2011-08-02'), 
(21, 4, 'S1', '2011-07-04'), 
(22, 4, 'S2', '2011-07-04'), 
(23, 4, 'S3', '2011-07-04'), 

(31, 5, 'S1', '2011-07-31'), 
(32, 5, 'S2', '2011-07-31'), 
(33, 5, 'S3', '2011-07-31'), 
(34, 5, 'S1', '2011-07-31'), 
(35, 5, 'S2', '2011-07-31'), 
(36, 5, 'S3', '2011-07-31'), 

(41, 6, 'S1', '2011-07-31'); 

Запрос

Для каждого GroupID мы находим верхние и нижние строки с помощью CROSS APPLY, то UNION ALL верхних и нижних результатов вместе.

WITH 
CTE_Groups 
AS 
(
    SELECT DISTINCT GroupID 
    FROM @T 
) 
SELECT 
    CA.ID 
    ,Groups.GroupID 
    ,CA.Status 
    ,CA.dt 
FROM 
    CTE_Groups AS Groups 
    CROSS APPLY 
    (
     SELECT TOP(1) 
      T.ID 
      ,T.Status 
      ,T.dt 
     FROM @T AS T 
     WHERE 
      T.GroupID = Groups.GroupID 
      AND T.dt >= @VarDate 
     ORDER BY T.dt, ID 
    ) AS CA 

UNION ALL 

SELECT 
    CA.ID 
    ,Groups.GroupID 
    ,CA.Status 
    ,CA.dt 
FROM 
    CTE_Groups AS Groups 
    CROSS APPLY 
    (
     SELECT TOP(1) 
      T.ID 
      ,T.Status 
      ,T.dt 
     FROM @T AS T 
     WHERE 
      T.GroupID = Groups.GroupID 
      AND T.dt <= @VarDate 
     ORDER BY T.dt DESC, ID DESC 
    ) AS CA 

ORDER BY GroupID, dt; 

Результат

+----+---------+--------+------------+ 
| ID | GroupID | Status |  dt  | 
+----+---------+--------+------------+ 
| 3 |  1 | S2  | 2011-07-30 | 
| 9 |  1 | S1  | 2011-08-02 | 
| 4 |  2 | S2  | 2011-07-30 | 
| 5 |  2 | S3  | 2011-08-01 | 
| 6 |  3 | S1  | 2011-08-02 | 
| 23 |  4 | S3  | 2011-07-04 | 
| 12 |  4 | S2  | 2011-08-02 | 
| 31 |  5 | S1  | 2011-07-31 | 
| 36 |  5 | S3  | 2011-07-31 | 
| 41 |  6 | S1  | 2011-07-31 | 
| 41 |  6 | S1  | 2011-07-31 | 
+----+---------+--------+------------+ 
Смежные вопросы