質問
ドキュメントのエントリを含む親テーブルと、ユーザーがドキュメントの1つにアクセスするたびに監査エントリを記録する履歴テーブルがあります。
結果セットで返された各ドキュメントにアクセスするための最新のユーザーIDを使用して、ドキュメントのリスト(さまざまな基準でフィルター処理)を返す検索クエリを作成しています。
したがって
DOCUMENTS
ID | NAME
1 | Document 1
2 | Document 2
3 | Document 3
4 | Document 4
5 | Document 5
HISTORY
DOC_ID | USER_ID | TIMESTAMP
1 | 12345 | TODAY
1 | 11111 | IN THE PAST
1 | 11111 | IN THE PAST
1 | 12345 | IN THE PAST
2 | 11111 | TODAY
2 | 12345 | IN THE PAST
3 | 12345 | IN THE PAST
次のように検索から返品を得たいと考えています
ID | NAME | LAST_USER_ID
1 | Document 1 | 12345
2 | Document 2 | 11111
3 | Document 3 | 12345
4 | Document 4 |
5 | Document 5 |
1つのSQLクエリと2つのテーブル間の結合を使用してこれを簡単に実行できますか?
解決
Andy Whiteが作成したものを改訂し、角括弧(MS SQL Server表記)をDB2(およびISO標準SQL)"区切り識別子"に置き換えます:
SELECT d.id, d.name, h.last_user_id
FROM Documents d LEFT JOIN
(SELECT r.doc_id AS id, user_id AS last_user_id
FROM History r JOIN
(SELECT doc_id, MAX("timestamp") AS "timestamp"
FROM History
GROUP BY doc_id
) AS l
ON r."timestamp" = l."timestamp"
AND r.doc_id = l.doc_id
) AS h
ON d.id = h.id
" timestamp"または「TIMESTAMP」」正しい-おそらく後者。
この利点は、Andyのバージョンの内部相関サブクエリを、(根本的に?)より効率的になる可能性のある、より単純な非相関サブクエリに置き換えることです。
他のヒント
「HAVING MAX(TIMESTAMP)」を取得できませんでした。 SQL Serverで実行するには-" having max(TIMESTAMP)>のようなブール式が必要だと思います。 2009-03-05"または何か、この場合には適用されません。 (私は何か間違っているかもしれません...)
これはうまくいくようです-結合には2つの条件があることに注意してください(これが良いかどうかわからない):
select
d.ID,
d.NAME,
h."USER_ID" as "LAST_USER_ID"
from Documents d
left join History h
on d.ID = h.DOC_ID
and h."TIMESTAMP" =
(
select max("TIMESTAMP")
from "HISTORY"
where "DOC_ID" = d.ID
)
これは結合を使用しませんが、このようなクエリでは、フィールドの選択をインライン化するのが好きです。ユーザーがアクセスしていない状況をキャッチしたい場合は、NVL()でラップできます。
select a.ID, a.NAME,
(select x.user_id
from HISTORY x
where x.doc_id = a.id
and x.timestamp = (select max(x1.timestamp)
from HISTORY x1
where x1.doc_id = x.doc_id)) as LAST_USER_ID
from DOCUMENTS a
where <your criteria here>
次のようになります。
SELECT ID, Name, b.USER_ID as LAST_USER_ID
FROM DOCUMENTS a LEFT JOIN
( SELECT DOC_ID, USER_ID
FROM HISTORY
GROUP BY DOC_ID, USER_ID
HAVING MAX( TIMESTAMP )) as b
ON a.ID = b.DOC_ID
これも機能する可能性があります:
SELECT ID, Name, b.USER_ID as LAST_USER_ID
FROM DOCUMENTS a
LEFT JOIN HISTORY b ON a.ID = b.DOC_ID
GROUP BY DOC_ID, USER_ID
HAVING MAX( TIMESTAMP )
Select ID, Name, User_ID
From Documents Left Outer Join
History a on ID = DOC_ID
Where ( TimeStamp = ( Select Max(TimeStamp)
From History b
Where a.DOC_ID = b.DOC_ID ) OR
TimeStamp Is NULL ) /* this accomodates the Left */