【问题标题】:Add empty row to query results if no results found如果没有找到结果,则在查询结果中添加空行
【发布时间】:2010-07-29 18:13:27
【问题描述】:

我正在编写由遗留系统调用的存储过程。遗留系统的限制之一是从存储过程返回的单个结果集中必须至少有一行。标准是在第一列中返回零(是的,我知道!)。

实现这一点的明显方法是创建一个临时表,将结果放入其中,测试临时表中的任何行,然后返回临时表中的结果或单个空结果。

另一种方法可能是在执行主查询之前针对主查询中的相同 where 子句执行 EXISTS。

这些都不是很令人满意。谁能想到更好的方法。我正在考虑类似这样的 UNION 的路线(我知道这不起作用):

--create table #test
--(
--  id int identity,
--  category varchar(10)
--)
--go
--insert #test values ('A')
--insert #test values ('B')
--insert #test values ('C')

declare @category varchar(10)

set @category = 'D'

select
    id, category
from #test
where category = @category
union
select
    0, ''
from #test
where @@rowcount = 0

【问题讨论】:

  • 在阅读@swe 的解决方案后考虑查看接受的答案!太好了,我承认我有想戳你这里的冲动;)stackoverflow.com/a/32586119/2979473
  • @ensisNoctis 除非我弄错了,否则该解决方案仅适用于您期望返回零或一个结果的情况
  • 很高兴,您是 - 请允许我与您分享我公司目前正在生产的代码,这一切都归功于 StackOverflow ;) 无法在此评论中全部包含,所以我发布了另一个答案,但它仍然是@swe,只是格式更好。 stackoverflow.com/a/37046650/2979473 如果存在(任何数字 >= 1),则返回所需表中的行,否则返回另一个表中的行(或文字,如我的示例)。
  • 啊哈,完全错过了 WITH TIES 提示。这很有趣,谢谢

标签: sql sql-server sql-server-2005 tsql


【解决方案1】:

恐怕很少有选择。

你总是要碰表两次,无论是 COUNT、EXISTS before、EXISTs in UNION、TOP 子句等

select
    id, category
from mytable
where category = @category
union all --edit, of course it's quicker
select
    0, ''
where NOT EXISTS (SELECT * FROM mytable where category = @category)

EXISTS 解决方案比 COUNT 更好,因为它会在找到一行时停止。 COUNT 将遍历所有行以实际计算它们

【讨论】:

  • 对我来说有一条新信息:EXISTS 在找到一行时停止。谢谢@gbn!
  • +1:当 WITH 没有任何数据时,我的 WITH/TOP 未能返回虚拟行。
  • 是的,我绝对更喜欢使用 EXISTS,因为它更快。很遗憾,我必须写两次相同的 where 子句。不过,我想我可能最终会选择这个,谢谢。
  • 如果您有一个不想重复的冗长复杂查询,您可以执行以下操作:;WITH cte AS (...) ... SELECT * FROM cte UNION ALL SELECT 0, '' WHERE NOT EXISTS (SELECT TOP 1 * FROM cte)
【解决方案2】:

这是一个老问题,但我有同样的问题。 没有双重选择的解决方案非常简单:

select top(1) WITH TIES * FROM (
select
id, category, 1 as orderdummy
from #test
where category = @category
union select 0, '', 2) ORDER BY orderdummy

通过“WITH TIES”,您将获得所有行(所有行都有 1 作为“orderdummy”,因此所有都是平局),或者如果没有结果,您将获得默认行。

【讨论】:

  • 这太棒了!简单、快速,并且比公认的答案更好,因为它不使用临时表,不重复查询也不声明变量(因此它可以很容易地在内联 TVF 中使用)!
  • 如果有人正在寻找适用于 Oracle 的 WITH TIES 语法(在 19c 中测试):select * from ( your_query_here ) order by orderdummy fetch first 1 row with ties;
【解决方案3】:

您可以使用完全外连接。大意是……

declare @category varchar(10)

set @category = 'D'

select #test.id, ISNULL(#test.category, @category) as category from (
    select
        id, category
    from #test
    where category = @category
)  
FULL OUTER JOIN (Select @category as CategoryHelper ) as EmptyHelper on 1=1   

目前我自己对此场景进行性能测试,因此不确定这会产生什么样的影响,但它会给您一个空白行,其中填充了类别。

【讨论】:

  • 这是一个非常有趣的解决方案,它避免了两次编写 where 子句。我很想知道这是否有效以及性能成本是多少?我无法弄清楚为什么将主查询包装在派生表中。有必要吗?
  • 主要查询包装是由于 where 子句,但可能会根据您如何构建底层查询而被重写。如果您没有加入正确的区域(后过滤),则该标准适用于两个表。成本似乎很小(实际执行计划中的成本为 0%)但是我的查询在其操作中相当复杂。
  • 是的,现在您已经包含了 isnull,这更有意义。谢谢
【解决方案4】:

这是@swe 的答案,只是格式更好。

CREATE FUNCTION [mail].[f_GetRecipients]
(
    @MailContentCode VARCHAR(50)
)
RETURNS TABLE
AS
RETURN
(
    SELECT TOP 1 WITH TIES -- returns all rows having highest priority found
        [To],
        CC,
        BCC
    FROM (
        SELECT
            [To],
            CC,
            BCC,
            1 AS Priority -- if no rows, priority 2 under UNION will get returned
        FROM mail.Recipients
        WHERE 1 = 1
            AND IsActive = 1
            AND MailContentCode = @MailContentCode

        UNION ALL

        SELECT
            *
        FROM (VALUES
            (N'system@company.com', NULL, NULL, 2),
            (N'author@company.com', NULL, NULL, 2)
        ) defaults([To], CC, BCC, Priority)
    ) emails
    ORDER BY Priority
)

【讨论】:

    【解决方案5】:

    我想你可以试试:

    Declare @count int
    set @count = 0
    
    Begin
    Select @count = Count([Column])
    From //Your query
    
    if(@Count = 0) 
       select 0
    else //run your query
    

    缺点是您有效地运行了两次查询,优点是您跳过了临时表。

    【讨论】:

    • 这与我在问题中建议的 EXISTS 语句类似。不同之处在于计数效率较低。
    【解决方案6】:

    为了避免重复选择查询,先用临时表存储查询结果如何?并且根据临时表,如果临时表为空则返回默认行,或者有结果时返回临时表?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-27
      • 1970-01-01
      • 2013-11-30
      相关资源
      最近更新 更多