2011-12-16 150 views
4

我有一個評分系統,任何人都可以在其中進行評論。每個人都可以由一個人多次評判。爲了計算平均值,我只想包含最新的值。SQL Server中的AVG和COUNT

這是可能的SQL?

  • 人1分人率2 5 1.2.2011 < - 忽略,因爲沒有人在2011年3月1日
  • 人2人率較新等級1
  • 人1分人率2 2 1 6上1.2.2011 < - 忽略以及
  • 人2分人率1 3 2011年3月1日
  • 人3人率1 5 2011年5月1日

結果:

  • 的平均人2是2
  • 的平均水平的人1 4.

表可能看起來像這樣:evaluator, evaluatee, rating, date

親切的問候

邁克爾

+0

請問您的表還擁有代理合成主鍵?一個自動遞增的身份整數,也許?如果這樣的話,它會使查詢更容易,更高效。 – 2011-12-16 11:13:14

+0

哪個版本的SQL Server? – AakashM 2011-12-16 11:39:30

回答

0

這是可以做到的,但它可真是哈利 - SQL不是設計來比較行,只列。我強烈建議您保留一個僅包含最新數據的附加表格,並將其餘表格存儲在一個存檔表格中。

如果你必須這樣做,那麼我需要一個完整的表結構來嘗試寫這個查詢。特別是我需要知道哪些是獨特的索引。

5

完全有可能。

讓我們假設你的表結構是這樣的:

INSERT INTO Ratings 
    SELECT 'Person 1', 'Person 2', 5, '2011-02-01' UNION 
    SELECT 'Person 1', 'Person 2', 2, '2011-03-01' UNION 
    SELECT 'Person 2', 'Person 1', 6, '2011-02-01' UNION 
    SELECT 'Person 2', 'Person 1', 3, '2011-03-01' UNION 
    SELECT 'Person 3', 'Person 1', 5, '2011-05-01' 

然後平均得分爲的人1:

SELECT AVG(Rating) FROM Ratings r1 
    WHERE Evaluatee='Person 1' and not exists 
    (SELECT 1 FROM Ratings r2 
     WHERE r1.Evaluatee = r2.Evaluatee AND 
      r1.evaluator=r2.evaluator AND 
      r1.date < r2.date) 

結果

CREATE TABLE [dbo].[Ratings](
    [Evaluator] varchar(10), 
    [Evaluatee] varchar(10), 
    [Rating] int, 
    [Date] datetime 
); 

像這樣的值:

4 

或所有被評的,由被評分組:

SELECT Evaluatee, AVG(Rating) FROM Ratings r1 
    WHERE not exists 
    (SELECT 1 FROM Ratings r2 
     WHERE r1.Evaluatee = r2.Evaluatee AND 
      r1.evaluator = r2.evaluator AND 
      r1.date < r2.date) 
    GROUP BY Evaluatee 

結果:

Person 1 4 
Person 2 2 

這可能看起來像它有一個隱含的假設,即具有相同的日期不存在條目;但這實際上並不是一個問題:如果這樣的條目可以存在,那麼無論如何你都不能決定這些條目中的哪一條是做的。你只能在它們之間隨意選擇。就像這裏顯示的那樣,它們都包含在內並且平均 - 這可能是您可以爲邊界案例獲得的最佳解決方案(儘管它略微偏袒那個人,給了他兩張選票)。爲了完全避免這個問題,您可以簡單地將主鍵的日期部分或唯一索引 - 這裏顯而易見的主鍵選擇是列(Evaluator,Evaluatee,Date)。

1
declare @T table 
(
    evaluator int, 
    evaluatee int, 
    rating int, 
    ratedate date 
) 

insert into @T values 
(1, 2, 5, '20110102'), 
(1, 2, 2, '20110103'), 
(2, 1, 6, '20110102'), 
(2, 1, 3, '20110103'), 
(3, 1, 5, '20110105') 

select evaluatee, 
     avg(rating) as avgrating 
from (  
     select evaluatee, 
      rating, 
      row_number() over(partition by evaluatee, evaluator 
           order by ratedate desc) as rn 
     from @T 
    ) as T 
where T.rn = 1 
group by evaluatee 

結果:

evaluatee avgrating 
----------- ----------- 
1   4 
2   2