2012-01-19 55 views
2

假設我有如下表:T-SQL如何獲得其他兩行「之間」的所有行

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上排序。

+0

如果部門IDS去115,100,119,102,119 ... 102將被列入?或者可以假設115和119總是成對出行? – MartW

+0

你如何確定最新的入學條件是什麼? –

+2

您是否有可以提供給ORDER BY子句的字段(或多個字段),以確保這些字段將按照您在上面顯示的順序顯示?除非可以通過ORDER BY建立訂單,否則這不能被用來工作。 *(SQL只能保證使用ORDER BY進行排序,而您的邏輯取決於該排序。)* – MatBailie

回答

3

它不漂亮,但它適用於您的示例數據。

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 
+0

Doh,我認爲只有在115行之後才返回行,並立即成功119行(因此每組只有一行)。我不知道哪個是對的,但是這適用於你的解釋:) – MatBailie

+1

在C3 ...'和AND>(SELECT MIN(rn)FROM C2)'? – MatBailie

+0

@Dems - 是的......當第一個115之前有119時,會處理這種情況......對嗎? :) –

2

我想避免相關的子查詢,但需要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 
+0

@sam - 我認爲你只需要115至119之間的單行,如果有更多的行,你不需要它們。這是正確的還是不正確的? – MatBailie

+0

實際上,我想要115和119之間的所有行,抱歉的混淆 – Sam

+0

@Sam - 那麼你想MikaelEriksson的答案:)相同的概念,但多行,而不是一個:) – MatBailie

1

嘗試:

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) 
相關問題