2012-01-19 30 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) 
相关问题