2012-04-25 14 views
8

デートアプリケーションでは、両方のクエリのLIMIT 10を組み合わせて1つの出力をクエリする必要があるテーブルがいくつかあります。別々にクエリするのは問題ではありませんが、現時点では難しいようですが、数値が正確ではないためLIMIT 10は機能しません(例:LIMIT 5とLIMIT 5ではなく、 、他方はシナリオに応じて10)。MySQL - 効率的にLIMITを使用して2つのSELECT文を1つの結果にまとめる

members table 
member_id | member_name 
------------------------ 
    1   Herb 
    2   Karen 
    3   Megan 

dating_requests 
request_id | member1 | member2 | request_time 
---------------------------------------------------- 
    1   1   2  2012-12-21 12:51:45 

dating_alerts 
alert_id | alerter_id | alertee_id | type | alert_time 
------------------------------------------------------- 
    5   3   2  platonic 2012-12-21 10:25:32 

dating_alerts_status 
status_id | alert_id | alertee_id | viewed | viewed_time 
----------------------------------------------------------- 
    4   5   2   0  0000-00-00 00:00:00 

あなたはカレンあるだけでログインして想像し、あなたはこれらの2つの項目が表示されるはずです。その代わり、ここで10のLIMITと1つのクエリで

1. Herb requested a date with you. 
2. Megan wants a platonic relationship with you. 

を組み合わせる必要が2つのクエリは、次のとおりです。

1. Herb requested a date with you. 
    -> query = "SELECT dr.request_id, dr.member1, dr.member2, m.member_name 
       FROM dating_requests dr 
       JOIN members m ON dr.member1=m.member_id 
       WHERE dr.member2=:loggedin_id 
       ORDER BY dr.request_time LIMIT 5"; 
2. Megan wants a platonic relationship with you. 
    -> query = "SELECT da.alert_id, da.alerter_id, da.alertee_id, da.type, 
         da.alert_time, m.member_name 
       FROM dating_alerts da 
       JOIN dating_alerts_status das ON da.alert_id=das.alert_id 
        AND da.alertee_id=das.alertee_id 
       JOIN members m ON da.alerter_id=m.member_id 
       WHERE da.alertee_id=:loggedin_id AND da.type='platonic' 
        AND das.viewed='0' AND das.viewed_time<da.alert_time 
       ORDER BY da.alert_time LIMIT 5"; 

再び、時には両方のテーブルが空であってもよく、または1つのテーブルが空、またはフル(ここでLIMIT 10回のキックで)と時間によって順序付けの両方であってもよいです。どのようにこのタスクを効率的に実行するためのクエリを得るためのアイデア?思考、アドバイス、チャイム、最適化を歓迎します。

+1

2つのクエリによって返された列が同じ場合は、それらを['UNION'](http://dev.mysql.com/doc/refman/5.6/en/union.html)に結合し、全体を'LIMIT'を実行する外部クエリに対するサブクエリです。そうでなければ、必要な 'LIMIT'を2番目のクエリに適用することができます(最初のクエリから返されたレコードの数から10を差し引いたもの) - おそらくクエリを呼び出すために使用する言語でこれを行うのが最も簡単です。 – eggyal

+0

期待どおりの結果を持つテーブルを作成します。あなたはそこに問題を見るでしょう。 –

+0

2つのクエリを異なる選択リストと組み合わせることはできません。 – vyegorov

答えて

17

UNIONと複数のクエリを組み合わせることはできますが、クエリの列数が同じ場合にのみ可能です。理想的には、列はデータ型だけでなく意味的意味でも同じです。しかし、MySQLはセマンティクスを気にせず、より一般的なものにキャストすることで異なるデータ型を扱うため、必要に応じては各テーブルと異なる意味を持つようにカラムをオーバーロードし、 (私はこのようにすることはお勧めしませんが)。

列の数が異なる場合、または2つのクエリからのデータのオーバーロードの整列を向上させたい場合は、SELECTステートメントにダミーリテラル列を挿入できます。たとえば:

SELECT t.cola, t.colb, NULL, t.colc, NULL FROM t; 

あなたも、彼らは他の場所でNULLある(ただし、カラム名は、最初のクエリから来るので、あなたがかもしれないことを覚えているように、第二のテーブルの最初のテーブルと他の人のために予約さいくつかの列を持つことができます)それらはすべてそこに命名していることを確認したい:

SELECT a, b, c, d, NULL AS e, NULL AS f, NULL AS g FROM t1 
UNION ALL -- specify ALL because default is DISTINCT, which is wasted here 
    SELECT NULL, NULL, NULL, NULL, a, b, c FROM t2; 

あなたはUNION演算子と組み合わせること、その後、この方法で、あなたの2つのクエリを合わせてみてください。 UNIONLIMITを適用することで、あなたがあなたの目標を達成するために近いです:まま

(SELECT ...) 
UNION 
    (SELECT ...) 
LIMIT 10; 

唯一の問題は、上記のように、第1のテーブルから10件の以上のレコードがレコードを「押し出す」だろう、ということです2番目からしかし、これを解決するために外部クエリにORDER BYを利用することができます。

すべて一緒にそれを置く:もちろん

(
    SELECT 
    dr.request_time AS event_time, m.member_name,  -- shared columns 
    dr.request_id, dr.member1, dr.member2,    -- request-only columns 
    NULL AS alert_id, NULL AS alerter_id,    -- alert-only columns 
     NULL AS alertee_id, NULL AS type 
    FROM dating_requests dr JOIN members m ON dr.member1=m.member_id 
    WHERE dr.member2=:loggedin_id 
    ORDER BY event_time LIMIT 10 -- save ourselves performing excessive UNION 
) UNION ALL (
    SELECT 
    da.alert_time AS event_time, m.member_name,  -- shared columns 
    NULL, NULL, NULL,         -- request-only columns 
    da.alert_id, da.alerter_id, da.alertee_id, da.type -- alert-only columns 
    FROM 
    dating_alerts da 
    JOIN dating_alerts_status das USING (alert_id, alertee_id) 
    JOIN members m ON da.alerter_id=m.member_id 
    WHERE 
    da.alertee_id=:loggedin_id 
    AND da.type='platonic' 
    AND das.viewed='0' 
    AND das.viewed_time<da.alert_time 
    ORDER BY event_time LIMIT 10 -- save ourselves performing excessive UNION 
) 
ORDER BY event_time 
LIMIT 10; 

、今それはあなたが結果セット内の各レコードを読み取るように扱っている行の種類を決定するのはあなた次第です(あなたがテスト勧めrequest_idおよび/ をNULLの値に設定するか、各レコードの元の表を明示的に示す結果に追加の列を追加できますが、idの列がNOT NULLの場合は同等である必要があります)。

+0

例と説明のためにありがとうございましたeggyal。行検索の背後にあるロジックは、ORDER BY句、要求時刻、およびアラート時刻が異なる表に挿入された順番になります。技術的には、最初のテーブルから3レコード、次に2テーブルから2レコード、次にLIMIT 10に達するまでテーブル間で1レコードのレコードがある可能性が非常に高いです。 – Wonka

+0

@Wonka:外側のクエリで 'ORDER BY'を使ってこれを達成できるはずですが、あなたがそれを理解できない場合は教えてください。 – eggyal

+0

あなたはORDER BY [time_here] LIMIT 10を意味しますか?内部のクエリはどうですか?単にORDER BY dr.request_time LIMIT 5とORDER BY da.alert_time LIMIT 5をドロップしますか?あなたは最終的なクエリが私のクエリでどのように見えるかを私に見せてもらえますか?私は自信がありますか? – Wonka

関連する問題