如果没有光标,如何在T-SQL中没有Cross Apply的情况下获取一些记录

时间:2012-11-13 10:42:02

标签: sql sql-server sql-server-2008 tsql

我有一个名为Objects的表,其中包含一些文件,例如:

  1. 用户
  2. 教师
  3. 还有另一个表(States),它保存这些对象的可能状态,如:

    1. 有效
    2. 空闲
    3. 教学
    4. 休息
    5. 创作
    6. 还有第三个表(联结表)记录每个对象的每个状态变化。在第三个表(ObjectStates)中,记录如下:

      1. 1,1,DateTime1(用户在DateTime1上处于活动状态)
      2. 2,5,DateTime2(教师在DateTime2上创作)
      3. 现在,我想要的是获取每个对象及其最新状态(不是状态历史记录)的查询。可以使用cursors或使用Cross Apply命令获得此结果。但是,我想知道是否还有其他方法可以从这三个表中获取每个对象的最新状态?因为cursors是costy。

4 个答案:

答案 0 :(得分:3)

使用row_number()窗口函数...

select * 
from
(

select objects.*,
       state.state,
       objectstates.changedate,
       row_number() over (partition by object.objectid order by changedate desc) rn
from 
    objects
         inner join
    objectstates
         on objects.id = objectstates.objectid
         inner join
    states 
         on objectstates.stateid = states.stateid
) v
where rn = 1

例如,如果因为使用SQL 2000而无法使用row_number,则可以在max/group by查询中使用联接。

select objects.*,
       state.state,
       objectstates.changedate,
from 
    objects
         inner join
    objectstates
         on objects.id = objectstates.objectid
         inner join
    states 
         on objectstates.stateid = states.stateid
    inner join
         (select objectid, max(changedate) as maxdate from objectstates group by objectid) maxstates
         on objectstates.objectid=maxstates.objectid
         and objectstates.changedate = maxstates.maxdate

答案 1 :(得分:3)

您可以两次加入ObjectStates表。表格的第一次加入将获得每个max(activedate)的{​​{1}}。第二次,您将加入objectidobjectid的值,这将获得与该值相关联的max(activedate)

state

请参阅SQL Fiddle with Demo

答案 2 :(得分:-1)

在过去的好时光中,我们只使用了Scalar子查询。

select o.*, (select top(1) s.description
               from objectstates os
               join states s on s.id = os.state_id
              where os.object_id = o.id
           order by os.recorded_time desc) last_state 
  from objects o;

哪个CROSS APPLY替换。要将其扩展到更多字段,必须将其扩展为类似

select *
  from (
select o.*, (select top(1) os.id
               from objectstates os
              where os.object_id = o.id
           order by os.recorded_time desc) last_state 
  from objects o
       ) x
   join objectstates os on os.id = x.last_state
   join states s on s.id = os.state_id;

答案 3 :(得分:-1)

您可以使用分区来查找每个Object的最新行,例如

create table #ObjectState
(
    Object int NOT NULL,
    State int NOT NULL,
    TimeStamp datetime NOT NULL
)

INSERT INTO #ObjectState (Object, State, TimeStamp) VALUES (1, 1, '2012-01-01')
INSERT INTO #ObjectState (Object, State, TimeStamp) VALUES (1, 2, '2012-01-02')
INSERT INTO #ObjectState (Object, State, TimeStamp) VALUES (1, 3, '2012-01-03')
INSERT INTO #ObjectState (Object, State, TimeStamp) VALUES (2, 4, '2012-01-01')
INSERT INTO #ObjectState (Object, State, TimeStamp) VALUES (2, 2, '2012-01-02')

select *, ROW_NUMBER() over (partition by Object order by TimeStamp desc) as RowNo from #ObjectState

select InnerSelect.Object, InnerSelect.State, InnerSelect.TimeStamp FROM
(
select *, ROW_NUMBER() over (partition by Object order by TimeStamp desc) as RowNo from #ObjectState
) InnerSelect
where InnerSelect.RowNo = 1


DROP TABLE #ObjectState

给出输出

Object  State  TimeStamp
1       3      2012-01-03 00:00:00.000
2       2      2012-01-02 00:00:00.000

为最后一次选择