2017-11-02 12 views
0

MySQL(バージョン:5.6.29および10.1.28-MariaDB)から上位n(現在は2)行を取得しようとしています。 私はSOや他の場所で簡単な例を見ました(、example2) 問題は、私のクエリがより複雑で、うまく動作していないようです。MySQLは上位グループnレコードをネストして選択します

Iは、(いくつかのフィールドを簡潔にするために除去される)図に見られるようなテーブルを持っている:

EER

各purchase_itemクーポン、purchase_offer又はsubscription_planのいずれかとすることができる(一方が有効であり、他の2つがヌルであります)。これらはそれぞれsubscription_days > 0です。

最も内側のSELECTは、それ自体が期待どおりに動作します。 2番目のSELECTは、(たとえ私が外側の選択を削除しても)期待通りに機能しません。purchase_rankは、同じ内側の選択がcustomer_uuidでソートされていないかのように同じcustomer_uuidのものとしばしば同じです。

アイデア?私はread ORDER BYはネストされたクエリでうまくいきませんが、それはおそらく私の場合の問題ですか?これをどうすればいいですか? クエリオプティマイザが何か変なことをしているのでしょうか?私はCASEをIFで置き換えようとしましたが、結果は同じです。 がここにコードされています

SELECT 
    id, 
    uuid, 
    purchase_offer, 
    subscription_plan, 
    coupon, 
    customer_uuid, 
    payment_date, 
    subscription_days, 
FROM 
    (SELECT 
     id, 
      uuid, 
      purchase_offer, 
      subscription_plan, 
      coupon, 
      customer_uuid, 
      payment_date, 
      subscription_days, 
      @purchase_rank := CASE @current_customer 
       WHEN customer_uuid THEN @purchase_rank + 1 
       ELSE 1 
      END AS purchase_rank, 
      @current_customer:= customer_uuid AS current_customer 
    FROM 
     (SELECT 
      pi.id, 
      pi.uuid, 
      pi.purchase_offer, 
      pi.subscription_plan, 
      pi.coupon, 
      pi.customer_uuid, 
      p.payment_date, 
      IFNULL(po.subscription_days, IFNULL(sp.subscription_days, cpo.subscription_days)) AS subscription_days 
    FROM 
     purchase_item pi 
    JOIN purchase p ON p.id = pi.purchase 
    LEFT JOIN purchase_offer po ON pi.purchase_offer = po.id 
    LEFT JOIN subscription_plan sp ON pi.subscription_plan = sp.id 
    LEFT JOIN coupon cp ON pi.coupon = cp.id 
    LEFT JOIN purchase_offer cpo ON cp.purchase_offer = cpo.id 
    WHERE 
     p.status = 'COMPLETED' 
      AND pi.customer_uuid IS NOT NULL 
      AND p.payment_date IS NOT NULL 
      AND (po.subscription_days > 0 
      OR sp.subscription_days > 0 
      OR cpo.subscription_days > 0) 
    ORDER BY pi.customer_uuid , p.payment_date DESC) AS temp) 
AS pu 
WHERE 
    pu.purchase_rank <= 2 
ORDER BY pu.customer_uuid , pu.payment_date DESC 

任意の助けいただければ幸いです。前もって感謝します。

答えて

0

は自分の質問に答えるために:私はthisを見つけました。 MariaDBだけでなく、MySQLでもうまく動作しているようです。ネストされたクエリには、テンポラリテーブルを作成するLIMIT <large number>が必要です。だからCataklysm's answerは部分的に正しいですが、それは(少なくとも私のテストによるものではないが)小さな数字では動作しません。ここで

は、コードの修正一部です:

... 
ORDER BY pi.vehicle_uuid , p.payment_date DESC LIMIT 18446744073709551615) temp) pu 

はあなたの助けをいただき、ありがとうございます。

0

MySqlクエリのこの種の制限に対しては、文の最後にLIMIT 0, 2を追加するだけで済みます。リミット文の詳細については

、チェックして自由に感じるthis documentation with realtime example.


EDIT I例えば

SELECT * FROM purchase 
ORDER BY payment_date ASC 
LIMIT n 
:ステートメントからの最初のn個の結果を取得します。

そして、それ以外の場合:

クエリの最初のn個の結果をスキップすることがわかっている場合は、特定のオフセットでLIMITを開始できます。一例として、我々は最初の10件の結果をスキップする:

SELECT * FROM purchase 
ORDER BY payment_date DESC 
LIMIT 10, n 
+0

ありがとうございますが、実際にはできません。 'LIMIT'を使うと、グループごとに最後の2レコード(' customer_uuid')ではなくすべてのレコードが制限されます。私が何かを誤解していない限り? –

+0

@RokMirt最後の2?あなたのグループの最初の結果が必要だと思いましたか?しかし、いずれにしても問題はありません。制限を開始する場所を選択できるので、いくつの結果があるかを知るか、別のORDER BYで作業するだけです。 – Cataklysim

+0

@Cataklysim申し訳ありませんが、私は最初のNを意味しました。しかし、あなたのやり方では、クエリはすべてのグループ(グループは 'customer_uuid')の最初のNを返しませんが、ALLグループの最初のNを取ります。 例:私は 'customer1'から3回、' customer2'から3回、 'customer3'から3回購入しました。購入は同じ順序で行われました。だから、もし私が最初の 'N = 2'を各顧客から購入し、あなたが言ったようにしたいのであれば(最も内側の' SELECT ... LIMIT 2')、6回の購買ではなく 'customer1'からの2回の購買だけを返します顧客) –

関連する問題