2009-02-18 53 views
2

我有一個表叫畫廊。對於圖庫中的每一行,表中有幾行圖片。一張圖片屬於一個畫廊。然後是表。那裏的每一行都是對某個畫廊的贊成或低估。 這裏是(簡化)結構:聚合與兩個聯接(MySQL)

gallery (gallery_id) 
picture (picture_id, picture_gallery_ref) 
vote (vote_id, vote_value, vote_gallery_ref) 

現在我想一個查詢給我下面的信息:用自己的數據字段的所有畫廊和連接到畫廊和sumarized值的圖片數量的選票。

這是我的查詢,但由於多次加入聚合值是不正確的。 (至少當有任何圖片或票數多於一行。)

SELECT 
    *, SUM(vote_value) as score, COUNT(picture_id) AS pictures 
FROM 
    gallery 
LEFT JOIN 
    vote 
    ON gallery_id = vote_gallery_ref 
LEFT JOIN 
    picture 
    ON gallery_id = picture_gallery_ref 
GROUP BY gallery_id 

因爲我已經注意到,COUNT(DISTINCT picture_id)給了我正確的數字圖片的我試過這樣:

(SUM(vote_value)/GREATEST(COUNT(DISTINCT picture_id), 1)) AS score 

它的工作原理在這個例子中,但是如果在一個查詢中有更多的連接呢?

只是想知道是否有更好或更「優雅」的方式可以解決這個問題。另外,我想知道我的解決方案是特定於MySQL還是標準SQL?

+0

您的GROUP BY正在使用您未定義的列,我假設您的意思是gallery_id。 – sfossen 2009-02-18 20:46:32

+0

是的,小錯誤 – okoman 2009-02-18 20:52:55

回答

5

本報價由Okham的威廉在這裏適用:

Enita非必須遵守multiplicanda praeter necessitatem

(拉丁語爲 「實體不被乘以超過需要」)。

您應該重新考慮爲什麼您需要在單個查詢中完成此操作?確實,單個查詢的開銷少於多個查詢,但是如果單個查詢的性質變得太複雜,無論是爲了開發還是爲了執行RDBMS,都會運行單獨的查詢。

3

或者只是使用子查詢......

我不知道這是否是有效的MySQL的語法,但你也許可以做類似的東西:

SELECT 
    gallery.*, a.score, b.pictures 
LEFT JOIN 
(
    select vote_gallery_ref, sum(vote_value) as score 
    from vote 
    group by vote_gallery_ref 
) a ON gallery_id = vote_gallery_ref 
LEFT JOIN 
(
    select picture_gallery_ref, count(picture_id) as pictures 
    from picture 
    group by picture_gallery_ref 
) b ON gallery_id = picture_gallery_ref 
0

正如比爾Karwin說,在一個查詢中完成這一切是非常難看的。

但是,如果你必須這樣做,加入和選擇聚合數據的非聚合數據需要加入反對子查詢(我在過去幾年沒有使用過多的SQL,所以我實際上忘記了這個適當的術語)。

讓我們假設你的庫表中有額外的字段namestate

select g.gallery_id, g.name, g.state, i.num_pictures, j.sum_vote_values 
from gallery g 
inner join (
    select g.gallery_id, count(p.picture_id) as 'num_pictures' 
    from gallery g 
    left join picture p on g.gallery_id = p.picture_gallery_ref 
    group by g.gallery_id) as i on g.gallery_id = i.gallery_id 
left join (
    select g.gallery_id, sum(v.vote_value) as 'sum_vote_values' 
    from gallery g 
    left join vote v on g.gallery_id = v.vote_gallery_ref 
    group by g.gallery_id 
) as j on g.gallery_id = j.gallery_id 

這將產生一個結果集,看起來像:

gallery_id, name, state, num_pictures, sum_vote_values 
1, 'Gallery A', 'NJ', 4, 19 
2, 'Gallery B', 'NY', 3, 32 
3, 'Empty gallery', 'CT', 0, 
1

你多久添加/更改表決記錄?

你多長時間一次添加/刪除圖片記錄?

您對這些總計運行此查詢的頻率如何?

在庫表上創建總計字段可能會更好(total_pictures, total_votes, total_vote_values)。

當您在圖片列表中添加或刪除記錄時,還會更新圖庫表格上的總數。這可以通過使用圖片桌上的觸發器來自動更新圖庫表來完成。也可以通過組合兩條SQL語句的事務來更新圖片表和圖庫表。當您在圖片表上添加記錄時,將增加圖庫表上的total_pictures字段。當您刪除圖片表上的記錄時,將減少total_pictures字段。

當投票記錄被添加或刪除或vote_value更改時,您可以更改total_votestotal_vote_values字段。添加記錄會增加total_votes字段並將vote_values添加到total_vote_values。刪除記錄會減少total_votes字段,並從total_vote_values中減去vote_values。在投票記錄上更新vote_values也應該更新total_vote_values與差異(減去舊值,添加新值)。

您的查詢現在變得微不足道 - 這只是來自圖庫表的簡單查詢。但這是以圖片和投票表更復雜的更新爲代價的。