2016-07-29 13 views
0

私は、「読者」オブジェクトの状態の履歴を含む簡単なテーブルを持っています。状態はACTIVEまたはINACTIVEにすることができます。今私は、一定の期間にアクティブだったすべての読者を選ぶクエリを持っていたいと思います。次の図は、私が意味していることを示しています:緑色の「ライフライン」を持つ「読者」は表示された期間中にACTIVEでした。彼らは質問で返されます。特定の期間における状態履歴テーブルのアクティブ状態の選択

enter image description here

tabel ReaderActivityこの(例のみ、上記画像と一致しない)ように見える:

reader_id | state | timestamp 
1  | ACTIVE | 1467331201089 
2  | ACTIVE | 1467332454545 
1  | INACTIVE | 1467348875254 
3  | ACTIVE | 1467350416546 
1  | ACTIVE | 1467351871123 
2  | INACTIVE | 1467352111545 

もちろん、このreader_idがマッピングされるReaderエンティティがあります。

私はこのためにJPAクエリを作成する必要がありますが、その期間内に(「INACTIVE」から「ACTIVE」への状態変化がない)結果に読者を含む問題があります。我々が調べる期間)。すべての立ち上がりエッジを持つ選択し、

  • まず:

    は、私も基本的には、クエリの部分を参照してください。これは単純です:SELECT DISTINCT a.reader FROM ReaderActivity a WHERE a.timestamp >= :startTimestamp AND a.timestamp < :endTimestamp AND a.state = 'ACTIVE'

  • 第2に、すべての読者の上のリストに、期間の開始前に最後の状態であるACTIVEを追加する必要があります。これは私が正しく取得しないものです:SELECT DISTINCT a.reader FROM ReaderActivity a WHERE a.timestamp >= :startTimestamp AND a.timestamp < :endTimestamp AND a.state = 'ACTIVE' or (SELECT aa.reader FROM ReaderActivity aa where aa.reader = a.reader AND aa.timestamp < :startTimestamp AND aa.state = 'ACTIVE' GROUP BY aa.reader ORDER BY max(aa.timestamp)) != null

これも返す赤サブクエリでAND aa.state = 'ACTIVE'で、我々はすでに除外するため、上記の画像で読者をマーク:私は(拳のクエリに統合)しようとしましたすべてのACTIVE状態なので、最後のACTIVE状態はもちろんACTIVEです。私は開始期間の前に最後の状態を選択し、それがアクティブであるかどうかをチェックする必要があります。しかしどうですか?

誰でも正しい方法で私を連れて来ることができますか? ありがとうございます!

答えて

1

クエリの最初の部分は、期間内に状態が有効に変更されたレコードを必要に応じて戻します。クエリの2番目の部分は、いくつかの精製が必要です。

あなたが求めていることをするには、「startTimeStamp」の瞬間まで、すべてのreader_idの最新の状態の変更を戻す必要があります。これらから、その時点で「アクティブ」と表示されているものを選択するだけです。このクエリは、指定した期間の開始時にアクティブであったすべての[reader_id]さんを返します

Select a.reader_id 
From ReaderActivity a 
Where a.timeStamp in 
( 
    Select max(b.timeStamp) 
    From ReaderActivity b 
    Where b.timestamp < :startTimeStamp 
    And b.reader_id = a.reader_id 
    Group By b.reader_id 
) 
and a.state = "ACTIVE" 

何かのように...。これを元のクエリのwhere句の中で実行することも、UNIONを使用してクエリの末尾に追加して、Select Distinct(reader_id)を実行することもできます。

テーブル内のグループの最大値から選択することは、いつも私にとって奇妙なことです。しかし、このクエリが役立つことを願っています!

+0

ありがとう、ルーク!私は '... where in()...'を使う可能性を見逃していました。[+1] - 私の完全な問い合わせは次のようになりました: 'SELECT DISTINCT a.reader FROM ReaderActivity a where a.timestamp> =:startTsとa.timestamp <:endTs AND a.state = 'ACTIVE' OR(a.timestamp IN(SELECT MAX(b.timestamp)FROM ReaderActivity b WHERE b.timestamp <:startTs GROUP BY b.r​​eader)AND a.state = 'ACTIVE') ' - 一つの質問:なぜあなたは' 'state'''を' 'と' 'state ... =' 'の最後の角かっこで囲んだのですか? – badera

+1

重要なヒントに対処できない*このクエリで注意すべき唯一の点は、何らかの理由でreader_id 'a'が正確なミリ秒... *で「無効」に設定されている場合です。 'where b.reader_id = a.reader_id'は、サブ選択のwhere節にありますか? – badera

+0

あなたの最初の質問に答えて、状態から括弧を削除してもクエリは変更されませんし、どちらも存在しません。列がスペースで区切られた単語で構成されている場合、1つの列をまとめてグループ化するために、列の周囲に角括弧が必要です。なんらかの理由で私は2つの単語(状態がわからない)として状態を読みます。あなたの2番目の質問に答えて、はい! a.reader_id = b.reader_idにwhereフィルタを追加すると、 'INACTIVE'レコードを戻すことができなくなります。これを反映するようにクエリを変更します。 @badera – Luke

1

このクエリは、それを行う必要があります。

SELECT r.reader_id, r.timestamp 
FROM ReaderActivity r 
WHERE r.timestamp>=:start AND 
     r.timestamp<=:stop AND 
     r.state='ACTIVE' 

UNION ALL 

SELECT r1.reader_id, r1.timestamp 
FROM ReaderActivity r1 
LEFT JOIN ReaderActivity r2 ON (r2.reader_id = r1.reader_id AND 
           r2.timestamp<:start AND 
           r2.timestamp>r1.timestamp) 
WHERE r1.timestamp<:start AND 
     r1.state='ACTIVE' AND 
     r2.id IS NULL 

UNIONのファースト・パートは、期間内で活性化し、UNIONの2番目の部分は時間の前にアクティブだけの読者を選択し、読者を選択します。

私はクエリをテストしていないので、少し調整する必要があるかもしれません。

+0

ありがとう、Victorqedu! [+1]申し訳ありませんが私はあなたの答えを「受け入れた」とマークしていませんでした。しかし、ルークからのものは少しベターです。 – badera

+0

タイムスタンプで選択することは安全ではありません - ルークが答えの最後に述べたように。 – Victorqedu

+0

サブクエリのフィルタが親選択のエントリに限定されているのはなぜですか? 2人の読者が同じタイムスタンプを持つ複数のエントリを生成することは技術的に不可能です。私はこれを対応する答えで直接議論する方がよりベターだと思います! – badera

関連する問題