2014-07-17 47 views
2

所以我有一個表格,裏面有一個積分系統。它看起來是沿着這條線:mysql - 只能得到與同一表中差異的結果

列:

ID Name Date  Points 
1 Peter 2014-07-15 5 
2 John 2014-07-15 6 
3 Bill 2014-07-15 3 

等等...

每天,新成果正在然而放到桌子點的acumulated總量,爲了能夠獲得歷史價值,結果被放入新的行中。所以,在2014年7月16日,該表將是這樣的:

ID Name Date  Points 
1 Peter 2014-07-15 5 
2 John 2014-07-15 6 
3 Bill 2014-07-15 3 
4 Peter 2014-07-16 11 
5 John 2014-07-16 12 
6 Bill 2014-07-16 3 

但是有時當玩家不參與了整整一天,並沒有得到任何積分,他仍然會被添加,但積分將保持不變(這裏顯示Bill的情況)

我的問題是如何計算每種類型的玩家數量(活動 - 彼得,約翰即當分值的變化從一個日期到另一個不活動的比爾 - 即當點值保持不變)

我已經設法讓這個查詢只選擇具有相同價值的玩家,但它給了我的球員名單而不是數量。雖然我可能potentialy是錯的這個查詢:

SELECT Points, name, COUNT(*) 
FROM points 
WHERE DATE(Date) = '2014-07-15' OR DATE(Date) = '2014-07-16' 
GROUP BY Points 
HAVING COUNT(*)>1 

我不知道如何計算行數(可以做PHP獲得的行數的旁路伎倆,但感興趣的SQL只),或如何反轉它,以獲得具有不同得分的玩家的數量(再次,可以獲得總計行數,然後減去上述數字,但對此不感興趣 - 我更喜歡SQL)。

感謝您的提前。

回答

2

你非常接近。

如果每個「玩家」每「日」最多隻能有一個排,你可以做這樣的事情:

SELECT SUM(IF(c.cnt_distinct_points<2,1,0)) AS cnt_inactive 
    , SUM(IF(c.cnt_distinct_points>1,1,0)) AS cnt_active 
    FROM (SELECT p.name 
       , COUNT(DISTINCT p.points) AS cnt_distinct_points 
      FROM points p 
      WHERE DATE(p.Date) IN ('2014-07-15','2014-07-16') 
      GROUP BY p.name 
     ) c 

內聯視圖查詢(別名爲c)獲得的計數每個玩家有不同數量的「積分」值。我們需要「按名稱分組」,這樣我們可以得到一個明確的球員名單,並指出分數值是否不同。如果給定玩家的所有非NULL「點」值相同,則COUNT(DISTINCT)將返回值1.否則,我們將得到大於1的值。

外部查詢處理該列表,將所有行摺疊成一行。 「竅門」是在SELECT列表中使用返回1或0的表達式,具體取決於播放器是否處於「非活動狀態」,並在其上執行SUM聚合。做同樣的事情,但是如果玩家是「積極的」,則返回1就是另一種表達方式。

如果玩家的不同點數是1,我們基本上會加1到cnt_inactive。同樣,對於玩家的不同點數大於1,我們將在cnt_active上加1。

如果這沒有意義,讓我知道如果你有問題。


注意:理想情況下,我們會盡量避免使用周圍的p.Date列引用的DATE()功能,這樣我們就可以使一個適當的索引。

如果Date列被定義爲(MySQL數據類型)DATE,那麼DATE()函數是不必要的。如果Date列被定義爲(MySQL的數據類型)DATETIMETIMESTAMP,我們可以使用一個等效謂詞:

WHERE p.Date >= '2014-07-15' AND p.Date < '2014-07-16' + INTERVAL 1 DAY 

這看起來比較複雜,但這種形式的謂語是可優化搜索(即MySQL能使用索引範圍掃描去滿足它,而不是看每行的表。)

出於性能考慮,我們可能從索引中受益的name前導列和date

... ON points (`name`,`date`) 

(MySQL可能能夠避免GROUP BY的「使用filesort」操作)。

+0

非常感謝您的答覆。我必須說,有關Date函數的其他信息在性能方面非常有用。 – Adimo

1

我會通過看以前的點數,然後做一個比較,解決這個問題:

select date(date), count(*) as NumActives; 
from (select p.*, 
      (select p2.points 
       from points p2 
       where p2.name = p.name and p2.date < p.date 
       order by p2.date desc 
       limit 1 
      ) as prev_points 
     from points p 
    ) p 
where prev_points is NULL or prev_points <> points; 

當然,你可以添加一個where條款可以爲任何特定的一天計數。

+0

你的答案似乎也不錯,但是我終於用@ spencer7593繼續了答案 – Adimo