2012-02-11 2 views
0

私はオンサイトのブラウジング習慣に基づいて商品をランク付けするためのクエリを作成しようとしています(私は以下の単純な非動的クエリの例を提供しています)。SELECTサブクエリの他のSELECTSを参照するMySQL

問題は、他の列を参照しているSELECTサブクエリのUNIONにあります。

誰もがこれを巧妙に回避する方法を知っていますか?

SELECT p.*, pi.piid, c.title AS cat_title, c.fn AS cat_fn, b.fn AS brand_fn, b.title AS brand_title, 
(
SELECT SUM(prod_rank) AS rank FROM (
    (
     SELECT 2.95 AS prod_rank FROM prod_link_cat WHERE pid = p.pid AND link_cid = 1 
    ) UNION ALL (
     SELECT 2.8 AS prod_rank FROM prod_link_cat WHERE p id = p.pid AND link_cid = 3 
    ) UNION ALL (
     SELECT 0.5 AS prod_rank FROM prod_link_cat WHERE pid = p.pid AND link_cid = 2 
    ) 
) AS tbl1 
) AS rank 
FROM prod p 
LEFT JOIN prod_link_cat plc ON plc.pid = p.pid AND plc.position = 1 
LEFT JOIN cat c ON plc.link_cid = c.cid AND c.live = 1 
LEFT JOIN brand b ON b.bid = p.bid AND b.live = 1 
LEFT JOIN prod_link_prod_img plpi ON plpi.pid = p.pid AND plpi.position = 1 
LEFT JOIN prod_img pi ON pi.piid = plpi.link_piid AND pi.live = 1 
WHERE p.live = 1 
GROUP BY p.pid 
ORDER BY (RAND() * rank) 
LIMIT 20 

答えて

1

あなたのインラインフィールドクエリを(組合で)削除するには、それを書き換えて、p.Live = 1の外側の "prod"基準と同じ基準に基づいて左結合として移動します。そうでなければp.Live =他の何か。

SELECT 
     p.*, 
     pi.piid, 
     c.title AS cat_title, 
     c.fn AS cat_fn, 
     b.fn AS brand_fn, 
     b.title AS brand_title, 
     COALESCE(PreQuery.ProdRankSum, 0) as ProdRankSum 
    FROM 
     prod p 
     LEFT JOIN 
     (SELECT 
       p2.id, 
       SUM(if(plc.link_cid = 1, 2.95, 0.00) 
        + if(plc.link_cid = 2, .50, 0.00) 
        + if(plc.link_cid = 3, 2.80, 0.00)) ProdRankSum 
       FROM 
       prod p2 
        JOIN prod_link_cat plc 
         ON p2.ID = plc.pid 
         AND plc.link_cid in (1, 2, 3) 
       WHERE 
       p2.Live = 1 
       GROUP BY 
       p2.id) PreQuery 
      ON p.id = PreQuery.id 

     LEFT JOIN prod_link_cat plc 
      ON p.pid = plc.pid AND plc.position = 1 
      LEFT JOIN cat c 
       ON plc.link_cid = c.cid AND c.live = 1 

     LEFT JOIN brand b 
      ON p.bid = b.bid AND b.live = 1 

     LEFT JOIN prod_link_prod_img plpi 
      ON p.pid = plpi.pid AND plpi.position = 1 
      LEFT JOIN prod_img pi 
       ON plpi.link_piid = pi.piid AND pi.live = 1 
    WHERE 
     p.live = 1 
    GROUP BY 
     p.pid 
    ORDER BY 
     (RAND() * COALESCE(PreQuery.ProdRankSum, 0)) 
    LIMIT 20 

さて、このすべての後に、あなたはおそらくそのような0.001として... 0以外のCOALESCE()の値を設定すると、ランクについて何かをする必要がありますそうでない場合、それは常にゼロになります商品リンクcat ...を持たない商品では、ランダムな時間0での注文は常にゼロになり、したがってトップになります。 (またはORDER BY ... DESCに変更)

明示的に1,2,3のリンクカテゴリを持つ商品のみを希望する場合は、このクエリも少し書き直します。お知らせ下さい。

さらに、最初のクエリでは、商品リンクcatにposition = 1、次にcatにLIVE = 1 ...の左結合を行い、残りの結合も左にします。あなたは左の結合をするつもりでしたか?

1

この特定のクエリでは、複雑で簡単な回避策があります。

私はprod_link_catlink_cidは必ずしも常に移入されません。このような何か、に見えると仮定していますあなたのクエリによって判断:あなたはこのテーブルから一定の値を選択しているとして、それを入力する理由はありません

pid|link_cid|other_columns... 
1 | 1 | ... 
1 | 2 | ... 
1 | 3 | ... 
2 | 1 | ... 

1231 + 21 + 32 + 31 + 2 + 3nothing:3回は...も一定この8つの可能な値があることを意味のみlink_cid値は1、2または3の存在に基づいています。

最高の解決策は、組み合わせたランキングスコアを持つユニークな別のテーブルを作成することです。これには2つの利点があります。最初に更新する必要がある場合は、すべてのコードを変更する必要はありません。第2に、ランキングをpidでユニークなテーブルに外部キーとして配置し、非常に簡単に取得できます。

同じ結果を得るために関数を使用することもできます。

クエリを最適化するには、問題のある部分を削除して、左外部結合にする必要があります。 3つのユニークなインデックススキャン、2つのユニオンと合計を失うので、おそらく努力する価値があります!