【问题标题】:SQL Server: Display 0 in Group by with Distinct valuesSQL Server:在 Group by 中显示 0 并具有不同的值
【发布时间】:2015-11-19 13:29:35
【问题描述】:

我有一张每天有很多条目的表格。每个条目都有一个“级别”。现在我要做的是,每天选择一个级别存在多少条记录。级别可以不同,所以首先我需要选择不同的所有级别,并每天显示每个级别有多少记录。如果一天没有按级别记录,则该值应为0。

为了说明我的需求: 我的表有以下内容

¦Date ¦ Level ¦ RecId ¦ ------------------------------ ¦2014-06-18 ¦ 1 ¦ 1 ¦2014-06-18 ¦ 1 ¦ 2 ¦2014-06-18 ¦ 2 ¦ 3 ¦2014-11-06 ¦ 1 ¦ 4 ¦2014-11-11 ¦ 2 ¦ 5 ¦2014-11-13 ¦ 3 ¦ 6

我想要的是:

¦ 日期 ¦ 级别 ¦ CountOfRecords ¦ -------------------------------------- ¦2014-06-18 ¦ 1 ¦ 2 ¦2014-06-18 ¦ 2 ¦ 1 ¦2014-08-18 ¦ 3 ¦ 0 ¦2014-11-06 ¦ 1 ¦ 1 ¦2014-11-06 ¦ 2 ¦ 0 ¦2014-11-06 ¦ 3 ¦ 0 ¦2014-11-11 ¦ 1 ¦ 0 ¦2014-11-11 ¦ 2 ¦ 1 ¦2014-11-11 ¦ 3 ¦ 0 ¦2014-11-13 ¦ 1 ¦ 0 ¦2014-11-13 ¦ 2 ¦ 0 ¦2014-11-13 ¦ 3 ¦ 1

我需要它的原因是在折线图中显示这些值,并且每个级别都是一条线。

感谢您的帮助,而我仍在继续使用 google...

干杯

【问题讨论】:

    标签: sql sql-server date group-by


    【解决方案1】:

    试试这个:

        SELECT T.[Date], 
               T.[Level], 
               COALESCE(COUNT(D.[Level]),0) AS CountOfRecords
        FROM (
              SELECT DISTINCT B.Date, A.[Level] 
              FROM tablename AS A 
                    INNER JOIN (SELECT DISTINCT [Date] 
                                FROM tablename) AS B ON 1=1
              ) 
              AS T LEFT JOIN tablename AS D ON T.[Level] = D.[Level] 
                                               AND T.[Date] = D.[Date]
        GROUP BY T.[Date], T.[Level]
        ORDER BY T.[Date], T.[Level]
    

    test is here

    【讨论】:

    • INNER JOIN ON 1=1cross join 来说过于复杂了
    • @GiorgiNakeuri Cross Join 可以在我的帖子中应用,就像在你的帖子中一样,使用逗号分隔符 (table1, table),也可以使用 Cross Apply 而不使用 search_condition。上面列出的所有连接的执行计划都是相同的。所以这并不过分复杂,这种编码方式只是习惯问题。
    • @Vasily,我同意。这样做只是一种不好的做法。使用逗号,它是 1990 年不推荐使用的旧 synrax。交叉应用将更难阅读。产生笛卡尔结果的自然方法是交叉连接。
    【解决方案2】:

    在实际表上产生 cross joindateslevels,然后是 left join

    ;with cte1 as(select distinct level from tablename),
          cte2 as(select distinct date from tablename)
    select c1.level, 
           c2.date,
           count(distinct t.RecId) as CountOfRecords 
    from cte1 c1
    cross join cte2 c2
    left join tablename t on t.date = c2.date and t.level = c1.level
    group by c1.level, c2.date
    

    编辑:

    DECLARE @t TABLE
        (
          Date DATE ,
          Level INT ,
          RecId INT
        )
    
    INSERT  INTO @t
    VALUES  ( '2014-06-18', 1, 1 ),
            ( '2014-06-18', 1, 2 ),
            ( '2014-06-18', 2, 3 ),
            ( '2014-11-06', 1, 4 ),
            ( '2014-11-11', 2, 5 ),
            ( '2014-11-13', 3, 6 )
    
    ;with cte1 as(select distinct level from @t),
          cte2 as(select distinct date from @t)
    select c1.level, 
           c2.date,
           count(distinct t.RecId) as CountOfRecords 
    from cte1 c1
    cross join cte2 c2
    left join @t t on t.date = c2.date and t.level = c1.level
    group by c1.level, c2.date
    

    输出:

    level   date    CountOfRecords
    1       2014-06-18  2
    2       2014-06-18  1
    3       2014-06-18  0
    1       2014-11-06  1
    2       2014-11-06  0
    3       2014-11-06  0
    1       2014-11-11  0
    2       2014-11-11  1
    3       2014-11-11  0
    1       2014-11-13  0
    2       2014-11-13  0
    3       2014-11-13  1
    

    【讨论】:

    • 非常感谢您的快速回答。不幸的是,它产生的输出并不完全正确。即使这一天有 4 条记录,CountOfRecords 的输出也是 1。但无论如何,瓦西里的答案非常有效。
    • @M.G,我不知道你在说什么,但是你的数据输出和你的完全一样!
    • 好的,很抱歉,我为我的数据库修改了您的代码而犯了一个错误。现在它也有效。非常感谢!
    【解决方案3】:

    试试这个:

    SELECT DISTINCT 
            [Date]
          , [level_ordinal] AS [level]
          , (SELECT COUNT([RecId]) 
                FROM [entries] AS E2 
                WHERE E2.[Level] = L.[level_ordinal]
                    AND E2.[Date] = E1.[Date]) AS CountOfRecords
      FROM [entries] AS E1
      CROSS JOIN [entries_levels] AS L
    

    与:

    CREATE TABLE entries_levels
    (
        [level_ordinal] [int] NULL
    )
    

    INSERT INTO entries_levels VALUES (1), (2), (3)
    

    【讨论】:

    • 感谢您的回答。 @Vasily 的答案非常有效
    • 至少不给我的答案投票是不礼貌的,因为它更快(比较执行计划)。好的,@Vasily 的回答很迷人,因为不使用第二张桌子(非常非常好@Vasily)但是可读性呢?第二个表的硬编码级别是一个好的设计问题,考虑到它们的值肯定与您的“业务逻辑”有关
    【解决方案4】:

    试试这个:

    创建样本表:

    CREATE TABLE NewTable
    (
    Date DATETIME,
    Level INT,
    RecID INT
    )
    

    插入样本数据:

    INSERT INTO NewTable
    VALUES
    ('2014-06-18', '1', '1'),
    ('2014-06-18', '1', '2'),
    ('2014-08-18', '2', '3'),
    ('2014-11-06', '1', '4'),
    ('2014-11-11', '2', '5'),
    ('2014-11-13', '3', '6')
    

    SQL 查询:

    SELECT
        Date,
        Level,
        COUNT(RecID) AS [CountOfRecords]
    FROM NewTable
    GROUP BY Date, Level
    

    输出:

    ======================
    |Date      |Lvl|Count|
    |2014-06-18|1  |2    |
    |2014-11-06|1  |1    |
    |2014-08-18|2  |1    |
    |2014-11-11|2  |1    |
    |2014-11-13|3  |1    |
    ======================
    

    PS:我认为您需要重新读取您的示例数据与您的预期输出,因为您已经迭代了日期 2014-06-18 的级别 1-3,但在一行中您有 2014-08-18 并继续作为3级所以计数不正确?

    【讨论】:

    • 这正是我所拥有的,但不幸的是这不是我所期望的。你是对的,有一个小类型的错误。谢谢
    • 感谢您的确认。我很高兴你得到了答案。
    猜你喜欢
    • 2015-08-10
    • 1970-01-01
    • 2018-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多