用户按月查询,包括不存在记录的默认值

时间:2014-04-11 08:41:31

标签: sql sql-server

好的,我的标题看起来有点奇怪,但我可以找到一个更好的方法来标题我的问题。

我当前的SQL语句如下所示:

SELECT 
    ActionBy,
    DATEADD(MONTH, DATEDIFF(MONTH, 0, ActionCreateDate), 0) AS 'dateStart',
    CONVERT(CHAR(3), (DATEADD(MONTH, DATEDIFF(MONTH, 0, ActionCreateDate), 0)), 100)  AS 'Month' , 
    YEAR(ActionCreateDate) AS 'YEAR',
    SUM([TimeTakenToComplete]) AS TOTAL
FROM 
    [myTable]
WHERE 
    [TimeTakenToComplete] IS NOT NULL 
    AND DeleteDate IS NULL 
    AND ActionBy IS NOT NULL
GROUP BY 
    ActionBy, DATEADD(MONTH, DATEDIFF(MONTH, 0, ActionCreateDate), 0),
    YEAR(ActionCreateDate)
ORDER BY 
    DATEADD(MONTH, DATEDIFF(MONTH, 0, ActionCreateDate), 0) ASC

最终结果如下所示:

user1 , 2013-06-01 00:00:00.000 , Jun , 2013 , 1000
user2 , 2013-06-01 00:00:00.000 , Jun , 2013 , 998
user3 , 2013-06-01 00:00:00.000 , Jun , 2013 , 600
user1 , 2013-07-01 00:00:00.000 , Jul , 2013 , 1110
user3 , 2013-07-01 00:00:00.000 , Jul , 2013 , 2330

我的问题是我希望所有用户都拥有默认值为0的所有月份的记录。

所以我想要的结果看起来像这样:

user1 , 2013-06-01 00:00:00.000 , Jun , 2013 , 1000
user2 , 2013-06-01 00:00:00.000 , Jun , 2013 , 998
user3 , 2013-06-01 00:00:00.000 , Jun , 2013 , 600
user1 , 2013-07-01 00:00:00.000 , Jul , 2013 , 1110
user2 , 2013-07-01 00:00:00.000 , Jul , 2013 , 0
user3 , 2013-07-01 00:00:00.000 , Jul , 2013 , 2330

有什么方法可以达到这个结果,还是我应该以编程方式解决这个问题?

3 个答案:

答案 0 :(得分:1)

实际上我在等待@Hamlet的解决方案..
但这就是我的想法(我没试过去试试) 如果任何用户一个月内没有任何数据,则根本没有数据(针对该特定月份)..

SELECT a.username,
    b.dateStart,
    b.Month , 
    b.YEAR,
    ISNULL(result.TOTAL,0)
FROM
(SELECT username FROM tableUser) a CROSS JOIN
(SELECT DISTINCT dateStart, CONVERT(CHAR(3), dateStart, 100)  AS 'Month', 'YEAR' FROM result) b
LEFT JOIN result
ON a.username=result.ActionBy AND b.dateStart=result.dateStart

注意:我将原始查询中的表格称为result,在原始查询中,您可以选择此选项:

SELECT 
    ActionBy,
    DATEADD(MONTH, DATEDIFF(MONTH, 0, ActionCreateDate), 0) AS 'dateStart', 
    YEAR(ActionCreateDate) AS 'YEAR',
    SUM([TimeTakenToComplete]) AS TOTAL
...

答案 1 :(得分:1)

诀窍是首先交叉加入表中所有不同值的用户的所有不同值,然后将结果左连接到表中:

SELECT 
    c.ActionBy, m.mon, SUM(h.TimeTakenToComplete) AS TOTAL
FROM 
    (select distinct ActionBy from myTable) c
    cross join (select distinct dateadd(month, datediff(month, 0, ActionCreateDate), 0) as mon from myTable) m
    left outer join myTable h 
    on h.ActionBy=c.ActionBy and dateadd(month, datediff(month, 0, ActionCreateDate), 0)=m.mon
WHERE 
    TimeTakenToComplete IS NOT NULL 
    AND DeleteDate IS NULL 
    AND ActionBy IS NOT NULL
GROUP BY 
    c.ActionBy, m.mon
ORDER BY 
    m.mon ASC

(select distinct ActionBy from myTable)替换为select on users表(如果有),并将(select distinct dateadd(month, datediff(month, 0, ActionCreateDate), 0) as mon from myTable)替换为Calendar表上的select(如果有)。

答案 2 :(得分:1)

检查此解决方案。它提供了所需的输出。

此外,我还使用表变量来模拟您的需求。我还使用@Users表来考虑你有一个用户表。如果您不想使用users表,那么您也可以使用mytable,但在其他月份应该至少有1个缺失用户的条目。

--Simulation of your myTable
DECLARE @myTable TABLE
(
    ActionBy VARCHAR(10),
    ActionCreateDate DATETIME,
    TimeTakenToComplete INT
)

--Simulation of users table
DECLARE @Users TABLE
(
    ActionBy VARCHAR(10)
)

--Dummy data for testing
INSERT INTO @myTable VALUES ('user1' , '2013-06-01', 100);
INSERT INTO @myTable VALUES ('user1' , '2013-06-01', 100);
INSERT INTO @myTable VALUES ('user1' , '2013-06-01', 100);
INSERT INTO @myTable VALUES ('user1' , '2013-06-01', 100);
INSERT INTO @myTable VALUES ('user1' , '2013-06-01', 100);

INSERT INTO @myTable VALUES ('user2' , '2013-06-01', 100);
INSERT INTO @myTable VALUES ('user2' , '2013-06-01', 100);
INSERT INTO @myTable VALUES ('user2' , '2013-06-01', 100);
INSERT INTO @myTable VALUES ('user2' , '2013-06-01', 100);
INSERT INTO @myTable VALUES ('user2' , '2013-06-01', 100);
INSERT INTO @myTable VALUES ('user2' , '2013-06-01', 100);

INSERT INTO @myTable VALUES ('user3' , '2013-06-01', 100);
INSERT INTO @myTable VALUES ('user3' , '2013-06-01', 100);
INSERT INTO @myTable VALUES ('user3' , '2013-06-01', 100);
INSERT INTO @myTable VALUES ('user3' , '2013-06-01', 100);


INSERT INTO @myTable VALUES ('user1' , '2013-07-01', 100);
INSERT INTO @myTable VALUES ('user1' , '2013-07-01', 100);
INSERT INTO @myTable VALUES ('user1' , '2013-07-01', 100);

INSERT INTO @myTable VALUES ('user3' , '2013-07-01', 100);
INSERT INTO @myTable VALUES ('user3' , '2013-07-01', 100);
INSERT INTO @myTable VALUES ('user3' , '2013-07-01', 100);
INSERT INTO @myTable VALUES ('user3' , '2013-07-01', 100);
INSERT INTO @myTable VALUES ('user3' , '2013-07-01', 100);


INSERT INTO @Users VALUES ('user1');
INSERT INTO @Users VALUES ('user2');
INSERT INTO @Users VALUES ('user3');

--Actual solution starts from here
; WITH MYCTE AS
(SELECT 
    ActionBy,
    DATEADD(MONTH, DATEDIFF(MONTH, 0, ActionCreateDate), 0) AS 'dateStart',
    CONVERT(CHAR(3), (DATEADD(MONTH, DATEDIFF(MONTH, 0, ActionCreateDate), 0)), 100)  AS 'Month' , 
    YEAR(ActionCreateDate) AS 'YEAR',
    SUM([TimeTakenToComplete]) AS TOTAL
FROM 
    @myTable
WHERE 
    [TimeTakenToComplete] IS NOT NULL 
    --AND DeleteDate IS NULL --uncomment this on using with your code
    AND ActionBy IS NOT NULL
GROUP BY 
    ActionBy, DATEADD(MONTH, DATEDIFF(MONTH, 0, ActionCreateDate), 0),
    YEAR(ActionCreateDate)
)

SELECT 
ISNULL(M1.ActionBy, L1.ActionBy) , 
ISNULL(M1.dateStart, L1.dateStart),
ISNULL(M1.Month, L1.Month),
ISNULL(M1.YEAR, L1.YEAR),
ISNULL(M1.TOTAL, 0)
FROM MYCTE M1
RIGHT OUTER JOIN
(
    SELECT * FROM
    (
    (SELECT DISTINCT [Month], dateStart, YEAR FROM MYCTE) m
    CROSS JOIN (SELECT ActionBy FROM @Users) U
    )
)L1
ON M1.[Month] = L1.[Month]
AND M1.ActionBy = L1.ActionBy

希望这有帮助