【问题标题】:Getting result with unmatched records as NULL将不匹配记录的结果设为 NULL
【发布时间】:2018-09-29 13:44:00
【问题描述】:

我正在尝试在 Wonderware 中的某个表中查询某些数据。我知道查询的“a”部分中有一些数据,其 TagName 等于“Weightdata2.uiID”。但是“b”部分没有匹配的数据,因此查询返回空数据集。但是如果没有匹配的数据,我想在 uiWater 列中获取 'a' 部分和 'b' 的数据,其中 NULL 或零。

这是我的查询:

DECLARE @StartDate DateTime
DECLARE @EndDate DateTime
set @StartDate = '2018-09-18 08:00:00.000'
set @EndDate = '2018-09-18 09:00:00.000'

SELECT a.Value as uiID, b.value as uiWater, cast(a.datetime as datetime2(0)) 
as dtCreated, 2 as Weightdata
FROM [INSQL].[Runtime].[dbo].[History] a
JOIN [INSQL].[Runtime].[dbo].[History] b ON a.datetime=b.datetime
WHERE a.TagName IN ('Weightdata2.uiID') and a.datetime>=@StartDate and 
a.datetime<=@EndDate and a.Value!=0
and b.TagName IN ('Weightdata2.uiWater') and b.datetime>=@StartDate and 
b.datetime<=@EndDate

【问题讨论】:

    标签: sql-server tsql wonderware


    【解决方案1】:

    这更有可能是PIVOT 的工作:

    ;with cteData as (
        SELECT t.datetime, t.TagName, t.value
        FROM [INSQL].[Runtime].[dbo].[History] t
        WHERE t.datetime>=@StartDate and t.datetime<=@EndDate
        AND t.TagName IN ('Weightdata2.uiID', 'Weightdata2.uiWater')
    )
    SELECT 
      d.dtCreated,
      NULLIF(p.[Weightdata2.uiID], 0) as uiID,
      p.[Weightdata2.uiWater] as uiWater
    FROM (
      SELECT 
        cast(d.datetime as datetime2(0)) as dtCreated,
        d.TagName, 
        d.value
      FROM cteData d
    ) d
    PIVOT (
      MAX(d.value) for d.TagName in ([Weightdata2.uiID], [Weightdata2.uiWater])
    ) p
    

    在所有情况下都将返回数据:当存在uiID 行但不存在uiWater 时,当两者都存在时,当不存在uiID 但存在uiWater 时。

    并且很容易调整为更长的标签列表。

    【讨论】:

      【解决方案2】:

      您只需将 JOIN 替换为 LEFT JOIN。如果值为null,您可以使用isnull返回0

      DECLARE @StartDate DateTime
      DECLARE @EndDate DateTime
      set @StartDate = '2018-09-18 08:00:00.000'
      set @EndDate = '2018-09-18 09:00:00.000'
      
      SELECT a.Value as uiID, ISNULL(b.value, 0) as uiWater, cast(a.datetime as datetime2(0)) 
      as dtCreated, 2 as Weightdata
      FROM [INSQL].[Runtime].[dbo].[History] a
      LEFT JOIN [INSQL].[Runtime].[dbo].[History] b ON a.datetime=b.datetime
      WHERE a.TagName IN ('Weightdata2.uiID') and a.datetime>=@StartDate and 
      a.datetime<=@EndDate and a.Value!=0
      and ((b.TagName IN ('Weightdata2.uiWater') and b.datetime>=@StartDate and 
      b.datetime<=@EndDate) OR b.datetime is null)
      

      【讨论】:

      • 没那么简单。由于两个表都参与了where 子句,要么需要对其进行修改以适应空值,要么需要将适当的条件移至on 子句。另外:关于COALESCE 和ISNULL 的好信息位于SQL Server Pro here 和MSDN 博客here。
      • WHERE 子句中b 列上的谓词必须移动到LEFT JOIN 的ON 子句中。由于NULL 比较将导致UNKNOWN,因此不会为不匹配的行返回任何行。
      • 我必须同意在 WHERE 子句中使用 ISNULL 和 COALESCE 的谨慎。它通常会导致查询变为非 SARGable,从而导致长时间运行的查询。
      【解决方案3】:

      可能只是这样:

      with Perimeter as (
          SELECT t.datetime, t.TagName, t.value
          FROM [INSQL].[Runtime].[dbo].[History] t
          WHERE t.datetime between @StartDate and @EndDate
          AND t.TagName IN ('Weightdata2.uiID', 'Weightdata2.uiWater')
      )
      select f1.Value as uiID, ISNULL(f2.value, 0) as uiWater, 
      cast(f1.datetime as datetime2(0)) as dtCreated, 2 as Weightdata
      from Perimeter f1 
      left outer join Perimeter f2 on f1.datetime=f2.datetime and f2.TagName='Weightdata2.uiWater'
      where f1.TagName='Weightdata2.uiID'
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多