2011-09-16 10 views
0

私はそれが私が理解するにはちょっと複雑すぎると書くためのクエリを持っています。ヘルプをいただければ幸いです。 私のテーブルには、本質的には、次のとおりです。準複雑な教義クエリ

Table: Foo 
Columns: id 
     timestamp 
     bar1 
     bar2 
     bar3 

BAR1、BAR2、およびBAR3は、レコードごとに一意ではありません。実際、3の組み合わせは具体的には複数のレコードに関係します。例:

0 | 2011-01-01 00:01:01 | 100 | 5 | 'Hello' 
1 | 2011-01-01 12:12:00 | 100 | 5 | 'Hello' 
2 | 2011-01-01 07:43:00 | 101 | 8 | 'Monkey' 
3 | 2011-01-01 17:46:08 | 102 | 9 | 'Cat' 
4 | 2011-01-01 23:15:00 | 100 | 5 | 'Hello' 
5 | 2011-01-01 10:00:00 | 100 | 6 | 'Goodbye' 

レコード0,1,4は関連していますが、2,3および5は一意です。私は、グループ内のすべてのレコードがタイムスタンプ<を持ってのIF BAR1の== 100、BAR2の== 5、及びBAR3 ==「こんにちは」を持つすべてのレコードを検索したいことを念頭に置いて

=現在の時間 ORグループ内のレコードの1つにタイムスタンプ< =現在の時刻 - 30分があります。

うまくいけばうまくいきます。そうでない場合は、私に知らせてください。私は明確にするために最善を尽くします。

編集:私はちょうどバーを有する例えば十分であろうことを期待していたが、実際には、私の実際のテーブルには、レコードが関連であることを示すために一致している必要があり、複数の列があります。私はそれに応じて例を更新しました。

+0

データはわかりませんが、{bar1、bar2、bar3}は別のテーブルに「正規化」できるグループを形成しています。 – wildplasser

答えて

1

は、私はあなたの質問のcorrectyを理解していれば、あなたはWANT(BAR1、BAR2、BAR3)=のすべてのレコード(100、5は、 'こんにちは')とあなたは、唯一の入力基準などの特定のcurrent_timeを持っています。

最初のステップとして、グループのメンバーを取得するには、グループの最大タイムスタンプが過去(最初の条件)であるか、グループの最小タイムスタンプが少なくとも30分前でなければなりません(あなたの第2の条件に等しい)。

ですから、このクエリでグループとそのタイムスタンプを表示することができます。

SELECT bar1, bar2, bar3, max(timestamp) group_end, min(timestamp) group_start 
     FROM foo 
     GROUP BY bar1, bar2, bar3; 

フィルターを追加:(\set:ためpsqlの特別な構文に注意してください - これはテスト専用です)

\set current_time '''2011-01-01 17:00:00''' 
    SELECT bar1, bar2, bar3, max(timestamp) group_end, min(timestamp) group_start 
     FROM foo 
     GROUP BY bar1, bar2, bar3 
     HAVING max(timestamp) <= :current_time OR min(timestamp) +'30min' <= :current_time 

グループが終了しておらず、十分に古い未完成のグループIDがないため、current_time = 2011-01-01 00:31:00には何も戻されません。その後、OR句のために(100,5、Hello)グループが返され、さらにcurrent_timeを増加させながらもう一方のグループが返されます。

これまでのところは良い - 最後のピースが見つかったすべてのグループのメンバーを取得することです:

SELECT * FROM foo WHERE (bar1, bar2, bar3) in (
     SELECT bar1, bar2, bar3 FROM foo 
     -- add WHERE clause with constraints based on bar1, bar2, bar3 here 
     GROUP BY bar1, bar2, bar3 
     HAVING max(timestamp) <= :current_time OR min(timestamp) +'30min' <= :current_time 
    ) 
    -- add further constraints here 

ご入力偶然にについての私の最初の仮定が間違っている場合は、もちろん、すべての適切なステップにフィルタを追加することができますクエリの以前の手順でのフィルタリングは、当然ながらより効果的です。適切なマーカーコメントを追加しました。

0

私はあまりpostgresqlに慣れていませんが、ここではT-SQLの答えがあります。これはあなたが探している結果を返すはずです。私はそれがpostgresqlで利用できないコマンドを使用しているとは思わないが、私は確信していない。また、サブセレクション内のDISTINCTが消えてしまうこともあります。必要でない場合は削除するだけです。がんばろう。

SELECT * 
FROM Foo 
WHERE 
(
bar IN (SELECT bar 
     FROM (SELECT bar, MAX(timestamp) As HighestTime FROM Foo GROUP BY bar) HT 
     WHERE HT.HighestTime <= GETDATE()) 
OR bar IN (SELECT DISTINCT bar FROM Foo WHERE timestamp <= DATEADD(mm, -30, GETDATE()) 
) 
AND 
bar = 100 

より低いか、単に最大のものをチェックして、現在の日時に等しいすべてのタイムスタンプを持っているものだけ小節番号を取得するために、サブ選択を使用して最初の「バー」。

第2の「バーイン」は、サブ選択を使用して、少なくとも1レコードのタイムスタンプを現在の時間(30分)以下に設定します。

"bar ="は特定のバー番号に制限します。

+0

バーが実際にbar1、bar2、bar3だった場合、どのように調整しますか? – clang1234