2

Objectsいくつかのファイルを含むというテーブルがあります。

  1. ユーザー
  2. 先生

Statesこれらのオブジェクトの可能な状態を保持する別のテーブル( )があります。

  1. アクティブ
  2. アイドル
  3. 教える
  4. 休憩
  5. オーサリング

そして、各オブジェクトの各状態変化をログに記録する3番目のテーブル(ジャンクションテーブル)があります。この3番目の表(ObjectStates)のレコードは次のようになります。

  1. 1、1、DateTime1(ユーザーはDateTime1でアクティブでした)
  2. 2、5、DateTime2(教師はDateTime2でオーサリングしていました)

さて、私が欲しいのは、(状態履歴ではなく)最新の状態で各オブジェクトを取得するためのクエリです。cursors、またはコマンドを使用してこの結果を取得することができCross Applyます。ただし、これら3つのテーブルから各オブジェクトの最新の状態を取得する他の方法があるかどうかを知りたいですか?高価だからcursorsです。

4

4 に答える 4

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

row_numberたとえば、SQL 2000 を使用しているために使用できない場合は、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
于 2012-11-13T10:50:25.197 に答える
3

ObjectStatesテーブルには 2 回参加できます。テーブルの最初の結合はmax(activedate)for eachを取得しますobjectidobjectid2 回目は、と の値の両方で結合し、その値に関連付けられた をmax(activedate)取得します。state

select o.name o_name,
  s.name s_name,
  os1.activedate
from objects o
left join
(
  select max(activeDate) activedate, objectid
  from objectstates
  group by objectid
) os1
  on o.id = os1.objectid
left join ObjectStates os2
  on os1.objectid = os2. objectid
  and os1.activedate = os2.activedate
left join states s
  on os2.stateid = s.id

デモで SQL Fiddle を参照してください

于 2012-11-13T10:51:33.720 に答える
-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;

どのCROSSAPPLYが置き換えられますか。より多くのフィールドに拡張するには、次のように拡張する必要がありました

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;
于 2012-11-13T10:54:26.600 に答える
-1

次のように、partition overを使用して、各オブジェクトの最新の行を見つけることができます。

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

最後の選択

于 2012-11-13T10:55:42.103 に答える