2013-07-29 7 views
7

私はこれでタオルを投げようとしています。Mysql:サブクエリから最大N値で注文

はじめに:私は(特にMySQLの、)クエリを持って、私は任意のNと、この作品を作りたいが、簡単のために、私は3

ようにNを設定しますする必要がありますテーブルからデータを取り込み、そのテーブルの上位3つの値に基づいてソートし、その後に他のソート基準にフォールバックします。すべての基本的な教科書のものはどれ

SELECT tbl.id 
FROM 
    tbl1 AS maintable 
    LEFT JOIN 
    tbl2 AS othertable 
    ON 
    maintable.id = othertable.id 
ORDER BY 
    othertable.timestamp DESC, 
    maintable.timestamp DESC 

だから基本的に私はこのような何かを持っています。しかし問題は、othertable.timestampの3つの最大値を取得してmaintable.timestampをフォールバックするだけで、最初のORDER BY節が必要になることです。

また、othertableにLIMIT 3サブクエリを実行して参加させることは、maintableに適用される任意の数のWHERE条件で動作する必要があるため、必要ありません。

私はそれがこのようなユーザ変数ベースのアプローチで動作させることはほとんどできましたが、それは最初に見つかった3つのothertable値取りますので、それは、アカウントの順序に入れていないので、それは失敗します。

そう...この上の任意のヒント:(ステートメントの前に= 0 @rank付き)

ORDER BY 
    (
    IF(othertable.timestamp IS NULL, 0, 
     IF(
     (@rank:[email protected]+1) > 3, null, othertable.timestamp 
    ) 
    ) 
) DESC 

?私はこの問題で私の心を失っている。これに対して私が持っているもう一つのパラメータは、既存の(非常に複雑な)クエリを変更するだけなので、ラッピングアウタークエリを実行できないということです。また、前述のように、私はMySQL上にあるので、ROW_NUMBER関数を使用するすべてのソリューションは残念ながら手の届かないところにあります。

ありがとうございます。

EDIT。

maintable 

id  timestamp 
1  100 
2  200 
3  300 
4  400 
5  500 
6  600 

othertable 

id  timestamp 
4  250 
5  350 
3  550 
1  700 

=> 

1 
3 
5 
6 
4 
2 

そして、何らかの理由で、私たちは、WHEREクエリに= 5をmaintable.idないで追加した場合、ここで我々が得るべきものです:ここで私は必要なものを説明するための単純な整数にダウン易しく書き直さタイムスタンプを持ついくつかのサンプルデータです

1 
3 
4 
6 
2 

...これは、このセットを参照しているothertableの上位3つの値のうちの1つです。

したがって、othertableからのIDが4の行は、タイムスタンプ値の降順で4番目であるため、順序に含まれていないため、基本タイムスタンプの順序に戻ります。

「maintable」のコンテンツと「othertable」は基本的にタイムスタンプが「特集の日付」のおすすめコンテンツのマーカーです。私は最後の3つの特集記事を上に浮かべるべきで、残りのリストはちょうど逆の年代順のリストであると考えています。

+2

私はこの問題を抱えています。サンプルデータと希望の結果を表示できますか? – Barmar

+0

maintableに適用される任意のWHERE条件で作業する必要がある理由は、othertableでLIMIT 3サブクエリを実行できないのはなぜですか? –

+1

ニースのブログ投稿:http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/ – Prasanth

答えて

1

多分このようなものです。

SELECT 
    id 
FROM 
    (SELECT 
    tbl.id, 
    CASE WHEN othertable.timestamp IS NULL THEN 
     0 
    ELSE 
     @i := @i + 1 
    END AS num, 
    othertable.timestamp as othertimestamp, 
    maintable.timestamp as maintimestamp 
    FROM 
    tbl1 AS maintable 
    CROSS JOIN (select @i := 0) i 
    LEFT JOIN tbl2 AS othertable 
     ON maintable.id = othertable.id 
    ORDER BY 
    othertable.timestamp DESC) t 
ORDER BY 
    CASE WHEN num > 0 AND num <= 3 THEN 
    othertimestamp 
    ELSE 
    maintimestamp 
    END DESC 
+0

残念ながら私のシナリオでは、このようなアプローチを防ぐ: "私がこれに対して持っているもう1つのパラメータは、既存の(非常に複雑な)クエリを変更するだけなので、ラッピングアウタークエリを実行できません。" –

1

修正答え:

select ilv.* from 
(select sq.*, @i:[email protected]+1 rn from 
(select @i := 0) i 
    CROSS JOIN 
(select m.*, o.id o_id, o.timestamp o_t 
    from maintable m 
    left join othertable o 
    on m.id = o.id 
    where 1=1 
    order by o.timestamp desc) sq 
) ilv 
order by case when o_t is not null and rn <=3 then rn else 4 end, 
     timestamp desc 

SQLFiddle here

が必要な複雑な選択条件に一致し、ページング要求に対する最終order by後に適切なlimit基準を追加するサブクエリsq内部where 1=1条件を改正します。

+0

「LIMIT 3サブクエリをothertableに実行して参加することは、これは、maintableに適用されるWHERE条件の任意の数で動作する必要があるため、必要ありません」という質問に明示的に述べられているように動作しません。 –

+0

修正されたバージョンはGolzTrolのものとかなり似ていますが、私は既存のシステムに沿ってどのように修正されるかをいくつか提案しました。 –

+0

私はこれを行う唯一の方法だと思いますが、それでもラッピングクエリを使用しているので、残念ながらこの文脈で私の人生を楽にしません。私はあなたに努力のためにアップヴォートを与えるつもりですが、いくつかの魔法の妖精が解き放たれた解決策で到着することを期待して、正しい答えを残しておきます。私はちょうどここで失っている戦いに戦っているかもしれません。しかし、ありがとう。 –

1

以下のようにユニオンクエリを使用できますか?

(SELECT id,timestamp,1 AS isFeatured FROM tbl2 ORDER BY timestamp DESC LIMIT 3) 
UNION ALL 
(SELECT id,timestamp,2 AS isFeatured FROM tbl1 WHERE NOT id in (SELECT id from tbl2 ORDER BY timestamp DESC LIMIT 3)) 
ORDER BY isFeatured,timestamp DESC 

これはやや冗長かもしれませんが、それは意味的にあなたが求める質問に近いです。これにより、返す機能の結果の数をパラメータ化することもできます。

関連する問題