2016-07-25 56 views
-1

这是我的第一篇文章,因此请轻松一下:-)。我试图得到一个SQL查询,它会给我每个用户每天的平均分数。数据正在用于绘制图表,因此我需要为每个用户提供一致的时间表。我遇到的问题是某些用户可能没有特定日期的任何数据,因此我需要这样才能返回0。以下是源数据和期望结果的示例(请注意,user02没有09/07/2016):SQL Server计算每个用户每天的平均分数,但某些用户在某些天没有记录分数

RAW data       Desired results 

USER DATE  SCORE   USER DATE  AVERAGE_SCORE 
user01 08/07/2016 0.66667  user01 08/07/2016 0.16667 
user01 08/07/2016 0.33333  user01 09/07/2016 0.66667 
user01 08/07/2016 -0.5   user01 10/07/2016 0.72222 
user01 09/07/2016 0.33333  user02 08/07/2016 0.10317 
user01 09/07/2016 0.66667  user02 09/07/2016 0.00000 <--return 0 
user01 09/07/2016 1    user02 10/07/2016 0.16270 
user01 10/07/2016 0.66667 
user01 10/07/2016 1 
user01 10/07/2016 0.5 
user02 08/07/2016 0.16667 
user02 08/07/2016 -0.14286 
user02 08/07/2016 0.28571 
user02 10/07/2016 0.66667 
user02 10/07/2016 0.57143 
user02 10/07/2016 -0.75 

在生产数据库中,表中可能有几十个用户,所以我需要考虑到这一点。我不确定解决这个问题的最佳方式,我之前已经完成了一些简单的SQL数据库工作,但是我正在努力解决这个问题。最受赞赏的任何帮助或建议。

+1

提示:'GROUP BY'。 –

+2

您可以使用一个计数表和日期添加函数来生成给定时间段内的所有日期,然后左键连接到您的查询 – ZLK

+0

我假设他有他需要的所有数据,最大分钟发布日期给出了一些天除以总和 - 否则他可以使用计算日期和查找自MIN以来的日期(日期) - 如果最近的日期没有数据 – Cato

回答

0
DECLARE @TBL TABLE (u NVARCHAR(50), d DATETIME, Score DECIMAL(10, 6)) 

INSERT INTO @TBL 
SELECT 'user01' u, '2016.07.08' d, 0.66667 SCORE union all  
select 'user01' u, '2016.07.08' d, 0.33333 SCORE union all  
select 'user01' u, '2016.07.08' d, -0.5  SCORE union all  
select 'user01' u, '2016.07.09' d, 0.33333 SCORE union all  
select 'user01' u, '2016.07.09' d, 0.66667 SCORE union all  
select 'user01' u, '2016.07.09' d, 1  SCORE union all  
select 'user01' u, '2016.07.10' d, 0.66667 SCORE union all 
select 'user01' u, '2016.07.10' d, 1  SCORE union all 
select 'user01' u, '2016.07.10' d, 0.5  SCORE union all 
select 'user02' u, '2016.07.08' d, 0.16667 SCORE union all 
select 'user02' u, '2016.07.08' d, -0.14286 SCORE union all 
select 'user02' u, '2016.07.08' d, 0.28571 SCORE union all 
select 'user02' u, '2016.07.10' d, 0.66667 SCORE union all 
select 'user02' u, '2016.07.10' d, 0.57143 SCORE 
; 
with cte as 
(
    select u.[user], d.[date] 
    from  (select distinct u as [user] from @TBL) as u 
    cross join (select distinct d as [date] from @TBL) as d 
) 
select cte.[USER], cte.[DATE], avg(isnull(raw.SCORE,0)) 
from cte 
left join @TBL as [raw] 
    on raw.[u] = cte.[user] 
and raw.[d] = cte.date 
group by cte.[USER], cte.[DATE] 
Order by cte.[USER], cte.[DATE]; 
+0

这看起来是可以工作的东西 - 我一直在寻找使用CTE来做到这一点,但不能完全得到正确的语法。这个在SSMS中给了我一大堆红色,所以我认为它的语法稍微有些不足。 – JezzaUK

+0

试一试;在cte和交叉连接之后是错误的(可能仍然是) – Paparazzi

+0

感谢@Paparazzi - 这让我有95%的地方需要,我最终将结果放到另一个临时表中进行处理。 – JezzaUK

0

尝试......

select 
    [USER], 
    DATE, 
    avg(SCORE) 
from tbl_name 
group by DATE,[USER] 
Order by DATE,[USER] 
+0

应该是日期,[用户]' –

+1

'user02 09/07/2016 0.00000'? – NEER

+0

阅读的问题..他的问题是为特定的日子没有得分的用户 – kostas

0
SELECT USERID, SUM(Scores)/(DATEDIFF(day,MIN(DATE),MAX(DATE))+1) 
as AVERAGE_PER_DAY 
    from table_name 
     GROUP BY USERID 

如果你想避免非活动的问题,在此期限结束一个合理的替代方案(如贴上去,直到2个星期前)

SELECT USERID, SUM(Scores)/(DATEDIFF(day,MIN(DATE),getdate())+1) 
as AVERAGE_PER_DAY 
    from table_name 
     GROUP BY USERID 
+0

我的推理是你需要(所有用户总分数)/(使用时间长度) - 根据第一篇和最后一篇文章,我花了很长时间使用天数(+1是因为我们需要计算FIRST和最后一天) – Cato

0

试试这个

DECLARE @MinDate DATETIME 
DECLARE @MaxDate DATETIME 

DECLARE @TBL TABLE (u NVARCHAR(50), d DATETIME, Score DECIMAL(10, 6)) 

INSERT INTO @TBL 
SELECT 'user01' u, '2016.07.08' d, 0.66667 SCORE union all  
select 'user01' u, '2016.07.08' d, 0.33333 SCORE union all  
select 'user01' u, '2016.07.08' d, -0.5  SCORE union all  
select 'user01' u, '2016.07.09' d, 0.33333 SCORE union all  
select 'user01' u, '2016.07.09' d, 0.66667 SCORE union all  
select 'user01' u, '2016.07.09' d, 1  SCORE union all  
select 'user01' u, '2016.07.10' d, 0.66667 SCORE union all 
select 'user01' u, '2016.07.10' d, 1  SCORE union all 
select 'user01' u, '2016.07.10' d, 0.5  SCORE union all 
select 'user02' u, '2016.07.08' d, 0.16667 SCORE union all 
select 'user02' u, '2016.07.08' d, -0.14286 SCORE union all 
select 'user02' u, '2016.07.08' d, 0.28571 SCORE union all 
select 'user02' u, '2016.07.10' d, 0.66667 SCORE union all 
select 'user02' u, '2016.07.10' d, 0.57143 SCORE 


SELECT 
    @MinDate = MIN(d), 
    @MaxDate = MAX(d) 
FROM @TBL 

;WITH Dates(dt) 
AS 
(
    SELECT @MinDate dt 
    UNION ALL 
    SELECT DATEADD(dd, 1, dt) AS dt 
    FROM Dates 
    WHERE 
     dt < @MaxDate 
) 

-- Query 

SELECT 
    u, 
    d, 
    AVG(SCORE) SCORE   
FROM 
    @TBL 
GROUP BY 
    u, 
    d 

UNION ALL 

SELECT 
    A.u, 
    D.dt, 
    0 Score 
FROM 
    Dates D CROSS JOIN 
    (SELECT DISTINCT u FROM @TBL) A 
WHERE 
    EXISTS 
    (
     SELECT * FROM 
     (
      SELECT 
       u, 
       d, 
       MIN(d) OVER (PARTITION BY u ORDER BY (SELECT null)) MinDate, 
       MAX(d) OVER (PARTITION BY u ORDER BY (SELECT null)) MaxDate 
      FROM 
       @TBL     
     ) T 
     WHERE 
      T.u = A.u AND     
      D.dt BETWEEN T.MinDate AND T.MaxDate     
    ) AND 
    D.dt NOT IN (
      SELECT T.d FROM @TBL T 
      WHERE 
       T.u = A.u 
    ) 
    ORDER BY u, d 

输出:

u   d   SCORE 
--------- ----------- ------------- 
user01 2016-07-08 0.166666 
user01 2016-07-09 0.666666 
user01 2016-07-10 0.722223 
user02 2016-07-08 0.103173 
user02 2016-07-09 0.000000 
user02 2016-07-10 0.619050