【问题标题】:More efficient way to query for a row that does not exist SQL查询不存在的行的更有效方法 SQL
【发布时间】:2017-08-16 16:44:56
【问题描述】:

我有这个查询,它连接回一个表以根据某些标准计算分数。在某些情况下,目标表中不存在需要返回某些内容的行,因此我在下面有当前查询,它会降低性能并且有时不会返回,因为此特定查询是 SSRS 中较大的查询评分集中的子查询和 SQL Server。

   SELECT
                G.[Name], 
                G.[ID], 
                A.IName, 
                A.ItID, 
                COUNT(A.IHid) OVER() AS ICount, 
                G.[AllComplete], 
                G.[IComplete], 
                G.[IStatus], 
                A.[Group], 
                A.[Status] AS [Status], 
                A.[Type] AS [Type]
   FROM TableA A
         INNER JOIN TableG G
                ON A.ID = G.ID AND G.id IS Not NULL
   WHERE G.[ID] = ('048') 
   AND NOT ( A.ItID = '' ) 
   AND NOT ( A.[Status] IN ('NA'))
   UNION ALL
   SELECT 'N/A', 'N/A', 'N/A', 'N/A', 0, NULL, NULL, 'N/A', 'N/A', 'N/A', 'N/A'
   WHERE NOT EXISTS (SELECT 1 
                              FROM TableA A 
                                    INNER JOIN TableG G 
                                           ON A.ID = G.ID AND G.id IS Not NULL
                               WHERE  G.[ID] = ('048') 
                               AND NOT ( A.ItID = '' ) 
                               AND NOT ( A.[Status] IN ('NA')))

【问题讨论】:

  • 这整件事是一个子查询?你怎么知道这是影响性能的部分?您可以在主查询之前将此作为 cte 吗?在没有上下文的情况下很难在这里提供很多帮助。
  • 通常,“某些行不存在”会暗示 LEFT JOIN,但这里不清楚哪些数据始终存在(如果有的话)。特别是如果这是子查询的一部分,通常您只返回空集(无行),而不是虚拟行。
  • 您的第一个 UNION 有一个 WHERE 子句,这与您的第二个 UNION 相同,但不存在?愿意给我们一个关于你在这里想要实现的目标的背景吗?您是否只想为不在您的第一个 UNION 中的 ID 设置一行“N/A”?如果是这种情况,则不需要您的第二个 UNION。
  • 整个查询的这一部分获取结果并将其用于评分。
  • N/A 如何用于评分?

标签: sql sql-server reporting-services ssrs-2012


【解决方案1】:

我认为你根本不需要 UNION。你的目标很模糊,但如果我理解正确,你想要的是从你的第一个表中返回所有值,其中 ID = 048 并且当它不匹配时那,你想要N/A。

如果这是真的,那么您不需要 UNION。只需从 A 到 G(或 G 到 A - 取决于您想要什么)进行 LEFT JOIN。这将返回表 A 中的所有数据(不适用),然后返回一个带有数据的数据——即 048

仅供参考:您的表不应该包含“”,如果是这种情况,您应该将其更新为 NULL,然后执行 NOT IN NULL,而不是 WHERE NOT (' ')

SELECT
            G.[Name], 
            G.[ID], 
            A.IName, 
            A.ItID, 
            COUNT(A.IHid) OVER() AS ICount, 
            G.[AllComplete], 
            G.[IComplete], 
            G.[IStatus], 
            A.[Group], 
            A.[Status] AS [Status], 
            A.[Type] AS [Type]
   FROM TableA A
      LEFT JOIN TableG G ON A.ID = G.ID AND G.[ID] = ('048') 
   WHERE  A.ItID NOT IN ('') -- this really should be NULL
   AND    A.[Status] NOT IN ('N/A')

【讨论】:

    【解决方案2】:

    如果我理解正确,您的“问题”与来自UNION ALL 的第二个查询有关。

    我已经在列上使用LEFT JOINISNULL / IIF 重新编写了您的查询,因此它们产生相同的输出(如果不支持IIF,您可以使用CASE):

    SELECT  ISNULL(G.[Name], 'N/A')                     AS Name, 
            ISNULL(G.[ID], 'N/A')                           AS ID, 
            IIF(G.ID IS NULL, 'N/A', A.IName)               AS IName, 
            IIF(G.ID IS NULL, 'N/A', A.ItID)                AS ItID, 
            IIF(G.ID IS NULL, 0, COUNT(A.IHid) OVER())  AS ICount, 
            G.[AllComplete], 
            G.[IComplete], 
            ISNULL(G.[IStatus], 'N/A')                  AS IStatus, 
            IIF(G.ID IS NULL, 'N/A', A.[Group])         AS [Group], 
            IIF(G.ID IS NULL, 'N/A', A.[Status])            AS [Status], 
            IIF(G.ID IS NULL, 'N/A', A.[Type])          AS [Type]
    FROM    TableA A
        LEFT JOIN TableG G
            ON A.ID = G.ID 
    WHERE       A.[ID] = ('048') -- replaced here G.ID with A.ID, since these need to be equal
        AND NOT  A.ItID = ''
        AND NOT  A.[Status] IN ('NA')
    

    有一件事,您可能想要提取从外部查询提供的标识符,您可以在处理中使用它。无法通过此示例真正说出哪个值来自外部查询。

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-13
      • 2020-05-21
      • 1970-01-01
      • 2013-08-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多