T-sql Как получить все строки «между» двумя другими строками - PullRequest
2 голосов
/ 19 января 2012

Предположим, у меня есть следующая таблица:

Table: Score
field: ID: uniqueidentifier
field: Departmentid: int
field: Score: float
field: EnteredOn: DateTime

Как я могу разработать запрос, который дает мне все оценки, которые находятся между записью в отдел 115 и отдел 119?: если у меня есть следующие записи:

Id, departmentid, score
<some guid>, 115, 1
<some guid>, 100, 2
<some guid>, 119, 3
<some guid>, 115, 2
<some guid>, 102, 1
<some guid>, 119, 4
<some guid>, 115, 2
<some guid>, 100, 4
<some guid>, 120, 4

Запрос должен получить следующие записи:

<some guid>, 100, 2
<some guid>, 102, 1

, так как они между 115 и 119 записями.* Записи будут отсортированы на EntereOn по умолчанию.

Ответы [ 3 ]

3 голосов
/ 19 января 2012

Это не красиво, но работает для ваших данных.

declare @Score table
(
  ID int identity primary key,
  DepartmentID int,
  Score int,
  EnteredOn int
)

insert into @Score values
(115, 1, 1),
(100, 2, 2),
(119, 3, 3),
(115, 2, 4),
(102, 1, 5),
(119, 4, 6),
(115, 2, 7),
(100, 4, 8),
(120, 4, 9)

;with C1 as
(
  select *,
         row_number() over(order by EnteredOn) as rn
  from @Score
), C2 as
(
  select rn,
         row_number() over(order by EnteredOn) as rn2
  from C1
  where DepartmentID = 115
), C3 as
(
  select rn,
         row_number() over(order by EnteredOn) as rn2
  from C1
  where DepartmentID = 119 and rn > (select min(rn) from C2)
), C4 as
(
  select C2.rn as FromRn,
         C3.rn as ToRn
  from C2 
    inner join C3
      on C2.rn2 = C3.rn2
)
select C1.ID, C1.DepartmentID, C1.Score
from C1
  inner join C4
    on C1.rn > C4.FromRn and
       C1.rn < C4.ToRn
2 голосов
/ 19 января 2012

Я хотел избежать коррелированных подзапросов, но, учитывая необходимость нескольких записей между 115 и 119, я думаю, что это необходимо. Вот альтернатива ответу MarkBanister (используя один коррелированный подзапрос, а не два, но с тремя объединениями вместо двух) .

Я не проверял, что работает лучше.

SELECT
  data_between.*
FROM
  Score      AS data_115
INNER JOIN
  Score      AS data_119
    ON data_119.EnteredOn = (SELECT MIN(EnteredOn) FROM Score WHERE DepartmentId IN (115, 119) AND EnteredOn > data_115.EnteredOn)
INNER JOIN
  Score      AS data_between
    ON  data_between.EnteredOn > data_115.EnteredOn
    AND data_between.EnteredOn < data_119.EnteredOn
WHERE
    data_115.DepartmentId = 115
AND data_119.DepartmentId = 119
1 голос
/ 19 января 2012

Попробуйте:

select m.*
from MyTable m
join (select ms.EnteredOn StartDate,
             (select min(me.EnteredOn) 
              from MyTable me 
              where me.Departmentid = 119 and 
                    me.EnteredOn > ms.EnteredOn) EndDate
      from MyTable ms
      where ms.Departmentid = 115) mr
on m.EnteredOn > mr.StartDate and m.EnteredOn < mr.EndDate
where not exists
(select null
 from MyTable mn 
 where mn.Departmentid = 115 and 
       mn.EnteredOn > mr.StartDate and 
       mn.EnteredOn < mr.EndDate)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...