2012-02-05 73 views
2

我很難完全知道如何在MySQL中完成以下操作,而且我已經採取了我的結果集並在之後用ruby操作它,這似乎並不理想。MySQL的查詢項目的平均價格是否小於X?

這是問題。隨着像「項目」的數據集:

id state_id price issue_date listed 
1 5   450 2011  1 
1 5   455 2011  1 
1 5   490 2011  1 
1 5   510 2012  0 
1 5   525 2012  1 
... 

我想要得到的東西

SELECT * FROM items 
WHERE ([some conditions], e.g. issue_date >= 2011 and listed=1) 
AND state_id = 5 
GROUP BY id 
HAVING AVG(price) <= 500 
ORDER BY price DESC 
LIMIT 25 

基本上我想要抓住一個項目的「組」下,其平均價格下降一定的門檻。我知道我上面的例子「group by」和「having」是不正確的,因爲它只會給AVG(price)這個項目,這沒有意義。我只是想說明我想要的結果。

這裏最重要的是我想在我的結果集中的單個項目的所有,我不只是希望看到一個行的平均價格,總等

目前我只是在沒有HAVING AVG(price)的情況下進行上述查詢,並逐個添加單個項目(以紅寶石形式),直到達到所需的平均值。如果我能弄清楚如何在SQL中執行此操作,那將非常棒。使用子查詢或聰明的東西如將表加入自身當然是可接受的解決方案,只要它們工作的很好!謝謝!

更新:在回答都鐸王朝的回答下面,這裏有一些澄清。除了目標平均值之外,總會有一個目標數量。而且我們總是會按照價格從低到高排序,並按日期排序。

因此,如果我們確實有10件商品的價格都是5美元,而我們想要查找5件商品的平均< 6美元,我們只需返回前5件商品。我們不會返回第一個,而且我們也不會返回與前兩個分組在一起的前三個。這基本上是我的代碼在Ruby中的工作。

回答

1

MySQL做的事很有道理。你想這樣做沒有意義的:

  • 如果你讓我們說4項,每項有5價格,你把HAVING AVERAGE <= 7你說的是查詢應返回ALL的排列一樣, :

    • {1} - 由於ID爲1個項目,可以是一組由本身
    • {1,2}
    • {1,3}
    • {1,4}
    • {1,2,3}
    • {1,2,4}

    ...

    • 等等?

您的計算紅寶石平均的算法也不是有效的,如果你有一個值5,1,7,10個項目 - 和尋求小於7的平均值,用價值元素10可以只返回一個元素爲1的組。但是,通過你的算法(如果我理解正確),具有值1的元素將返回到第一組中。

更新

你想要的是什麼樣的Knapsack problem和你的方法是使用某種Greedy Algorithm來解決它。我不認爲有直接,簡單和正確的方法來在SQL中實現它。

經過谷歌搜索,我發現this article,它試圖解決用SQL編寫的AI的揹包問題。

通過考慮你的項目的價格作爲權重,其項目數和所需的平均,你可以計算,可以在「揹包」乘以desired_costnumber_of_items

+0

感謝您的回答。這是對發生的事情的一個很好的解釋,但請查看我的最新問題以獲得澄清。例如,我們可能會有一個「3」的目標數量,在這種情況下,會有一個「正確的」答案:{1,2,3}。如果找不到精確的匹配,我確實想做一些事情,比如找到「最接近的匹配」,但這可以通過附加查詢來完成。 – kaptron 2012-02-05 01:43:00

+1

再次感謝。我認爲你真的已經掌握了這個問題。我不確定我的原始方法是否正確,但您肯定指出我正確的方向。 – kaptron 2012-02-06 05:36:31

+0

我很高興它幫助:) – 2012-02-06 07:46:38

0

我不是從你的問題完全肯定,但我認爲這是你的問題的解決方案:

SELECT * FROM items 
WHERE (some "conditions", e.g. issue_date > 2011 and listed=1) 
AND state_id = 5 
AND id IN (SELECT id 
      FROM items 
      GROUP BY id 
      HAVING AVG(price) <= 500) 

ORDER BY price DESC 
LIMIT 25 

注:這是從我的頭頂,我沒有做複雜的SQL有一段時間,所以它可能是錯誤的。不過,我認爲這個或者類似的東西應該可以工作。

+0

是的,我試過類似的東西;問題在於該查詢中的「HAVING AVG(price)<=」基本上與「WHERE price <=」相同,因爲它只是按單個項目進行分組。 – kaptron 2012-02-05 01:39:43

+0

我用你提供的數據集製作了一個數據庫,查詢返回了我以爲你在找的東西。我不確定在這種情況下我明白你在找什麼。你可以試着解釋你想要的嗎? – Jasper 2012-02-05 02:07:07

2

我會做輸入最大值幾乎與賈斯珀所提供的相反......用你的標準開始你的查詢,以顯式地限制少數可能符合條件的項目,而不是獲取所有項目並在每個條目上運行子選擇。可以僞裝成一個較大的性能命中......可能是錯的,但這裏是我的產品..

select 
     i2.* 
    from 
     (SELECT i.id 
      FROM items i 
      WHERE 
       i.issue_date > 2011 
      AND i.listed = 1 
      AND i.state_id = 5 
      GROUP BY 
       i.id 
      HAVING 
       AVG(i.price) <= 500) PreQualify 

     JOIN items i2 
     on PreQualify.id = i2.id 
      AND i2.issue_date > 2011 
      AND i2.listed = 1 
      AND i2.state_id = 5 
    order by 
     i2.price desc 
    limit 
     25 

不知道的順序通過,特別是如果你想通過項目......除了分組,我將確保在索引(STATE_ID,上市,ID,ISSUE_DATE)每評論

我想我就可以正確

澄清。不要將「HAVING」子句與「WHERE」混淆。在哪裏說DO或DONT包括基於特定條件。 HAVING意味着在所有where子句和分組完成後,結果集將「潛在地」接受答案。然後檢查HAVING,如果IT STILL符合條件,則包含在結果集中,否則將其拋出。從INNER查詢中單獨嘗試以下內容...執行一次WITHOUT HAVING子句,然後再次使用HAVING子句...

SELECT i.id, avg(i.price) 
    FROM items i 
    WHERE i.issue_date > 2011 
    AND i.listed = 1 
    AND i.state_id = 5 
    GROUP BY 
     i.id 
    HAVING 
     AVG(i.price) <= 500 

當你獲得更多的進入編寫查詢,試件單獨看你做了什麼VS你在想什麼......你會發現如何/爲什麼某些事情的工作。此外,您現在正在更新的問題中討論如何在明顯的低和高範圍內獲取多個ID和價格......但您也正在應用限制。如果你有20個物品,每個物品有10個合格記錄,你的25個限制將顯示所有的第一個項目和5個到第二個......這不是我認爲你想要的......你可能需要25個合格的記錄「ID」。這將包裝這個查詢到另一個級別...

+0

看起來不錯,但我認爲它有一個類似的問題,賈斯珀的。 AVG(i.price)沒有真正獲得整套項目的AVG。如果按照state_id進行分組,它可能更合適,但它不會找到屬於AVG 500的X項目,如果來自state_id = 5的所有項目的AVG <= 500,它基本上只會告訴您一個積極的結果。 – kaptron 2012-02-05 01:57:04

+0

@Kaptron,然後從內部刪除「State_ID」限定符...無論您的INTERNAL查詢得到的平均數IS將返回任何您想要的ID。然後使用THAT結果重新出來,並把你的其他標準包括你的State_ID元素。 – DRapp 2012-02-05 03:09:36

+0

也許我還沒有完全清楚.Tudor的答案似乎理解了這個問題。基本上,我試圖做一個查詢,其中總項目*平均*出到<= 500,這意味着它可以包括價格490,500和510的項目。我在這裏看到的查詢只包括單獨的項目價格<= 500,而不是整個集合中的平均值爲500。 – kaptron 2012-02-05 06:13:34