【问题标题】:Add new rows to resultset in MSSQL在 MSSQL 中向结果集中添加新行
【发布时间】:2013-07-15 10:37:16
【问题描述】:

我在 MSSQL 2008 R2 中运行 SQL 查询,它应该始终返回一致的结果集,这意味着应该显示选定日期范围内的所有日期,尽管数据库中没有特定日期内的行/值日期范围。例如,当 id 为 1 和 2 时,日期 2013-07-03 - 2013-07-04 应如下所示。

场景 1

Date-hour, value, id
2013-07-03-1, 10, 1
2013-07-03-2, 12, 1
2013-07-03-...
2013-07-03-24, 9, 1
2013-07-04-1, 10, 1
2013-07-04-2, 10, 1
2013-07-04-...
2013-07-04-24, 10, 1

2013-07-03-1, 11, 2 
2013-07-03-2, 12, 2
2013-07-03-...
2013-07-03-24, 9, 2
2013-07-04-1, 10, 2
2013-07-04-2, 12, 2
2013-07-04-...
2013-07-04-24, 10, 2

但是,如果 id 2 缺少 2013-07-04 的值,我通常只会得到如下所示的结果集: 场景 2

Date-hour, value, id
2013-07-03-1, 10, 1
2013-07-03-2, 12, 1
2013-07-03-...
2013-07-03-24, 9, 1
2013-07-04-1, 10, 1
2013-07-04-2, 10, 1
2013-07-04-...
2013-07-04-24, 10, 1

2013-07-03-1, 11, 2 
2013-07-03-2, 12, 2
2013-07-03-...
2013-07-03-24, 9, 2

场景 2 将创建一个不一致的结果集,这将影响输出。是否有任何方法可以使 SQL 查询即使在缺少值的情况下也始终返回为场景 1,所以如果日期范围内的特定日期没有值,至少返回 NULL。如果结果集返回 id 1 和 2,则应涵盖 id 1 和 2 的所有日期。如果返回 id 1、2 和 3,则应涵盖 id 1、2 和 3 的所有日期。

我有两张表,如下所示:

tbl_measurement
    id, date, hour1, hour2, ..., hour24

tbl_plane
    planeId, id, maxSpeed

我正在运行的 SQL 查询如下所示:

SELECT DISTINCT hour00_01, hour01_02, mr.date, mr.id, maxSpeed 
FROM tbl_measurement as mr, tbl_plane as p 
WHERE (date >= '2013-07-03' AND date <= '2013-07-04') AND p.id = mr.id 
GROUP BY mr.id, mr.date, hour00_01, hour01_02, p.maxSpeed
ORDER BY mr.id, mr.date 

我已经环顾四周了,也许 PIVOT 表是解决这个问题的方法?你能帮帮我吗?如果您能帮助我了解如何为此目的编写 SQL 查询,我将不胜感激。

【问题讨论】:

    标签: sql-server pivot


    【解决方案1】:

    您可以使用递归 CTE 生成日期列表。如果您cross join 使用飞机,则每架飞机的每个日期都会得到一排。使用left join,您可以链接测量(如果存在)。即使没有找到测量值,left join 也会离开该行。

    例如:

    declare @startDt date = '2013-01-01'
    declare @endDt date = '2013-06-30'
    
    ; with  AllDates as
            (
            select  @startDt as dt
            union all
            select  dateadd(day, 1, dt)
            from    AllDates
            where   dateadd(day, 1, dt) <= @endDt
            )
    select  *
    from    AllDates ad
    cross join
            tbl_plane p
    left join
            (
            select  row_number() over (partition by Id, cast([date] as date) order by id) rn
            ,       *
            from    tbl_measurement
            where   m.inputType = 'forecast'
            ) m
    on      p.Id = m.Id
            and m.date = ad.dt
            and m.rn = 1 -- Only one per day
    where   p.planeType = 3
    option  (maxrecursion 0)
    

    【讨论】:

    • 当我运行此查询时,我收到错误:“必须声明标量变量“@startDt”。”。我在哪里声明这个?我在哪里添加我的日期范围?是否要与我当前的查询结合使用,不确定我是否理解。
    • 您在运行查询时是否包含declare 行?如果您愿意,可以将 @startDt@endDt 替换为硬编码值。
    • 很好,它运行良好,正是我想要的。我想调整的唯一一件事(为简单起见,我在原始描述中省略了)是还过滤返回的值,以便只包含 p.planeType = '3' 和 m.inputType = 'forecast' 。我尝试在“...and m.date = ad.dt and p.planeType = '3' and m.inputType = 'forecast'”之后添加它,但它仍然返回所有行。还尝试了“...and m.date = ad.dt where p.planeType = '3' and m.inputType = 'forecast'”,但它不再起作用了。我可以在哪里添加此过滤器?
    • 平面条件进入where 子句。测量过滤进入连接条件(在on 之后)。如果您将测量条件放在where 子句中,您将过滤掉没有匹配测量的日期。
    • 很好,工作正常。感谢 Andomar 提供了一个很好的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多