2012-02-11 120 views
0

我試圖創建一個查詢來根據現場瀏覽習慣(我在下面提供了一個簡化的非動態查詢示例)對產品進行排名。MySQL引用SELECT子查詢中的其他選擇

我遇到的問題是在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以外的COALESCE()值...如0.001否則,它將永遠是零對於那些沒有產品鏈接的產品...並且隨機時間排序0總是爲零,因此排在最前面。 (或更改爲ORDER BY ... DESC)

但是,如果您只希望那些明確擁有鏈接類別1,2或3的產品,我也會稍微重寫此查詢。讓我知道。

此外,您的原始查詢是左連接到產品鏈接貓的位置= 1,然後貓到哪裏貓是LIVE = 1 ...並留下了其他人加入。你是否打算進行左連接?

1

對於這個特定的查詢有一個參與但簡單的解決方法。

看您的查詢我假設prod_link_cat看起來像這樣,在link_cid不一定總是被填充:

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

當你選擇從該表中的恆定值,我們沒有理由將其輸入3倍...另外,常數僅基於link_cid值1,2或3的存在這意味着有8倍可能的值:1231 + 21 + 32 + 31 + 2 + 3nothing

最好的解決方案是在這些組合中創建另一個表,這些組合具有綜合排名分數。這有兩個好處,首先如果你需要更新它,那麼你不必輪流改變你的所有代碼。其次,您可以將排名作爲外鍵放到pid上獨一無二的表格中,並且非常容易。

您也可以使用函數來實現相同的結果。

因此,要優化您的查詢,您必須刪除違規部分並將其變爲左外部連接。你會失去3個獨特的索引掃描,2個工會和一筆錢,所以它可能是值得的努力!