如果没有找到结果,则在查询结果中添加空行

问题描述 投票:0回答:7

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

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

另一种方法可能是在执行主查询之前对主查询中的相同 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
sql sql-server sql-server-2005 t-sql
7个回答
36
投票

恐怕选择很少。

你总是必须接触表两次,无论是 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 将遍历所有行以实际计数


21
投票

这是一个老问题,但我也遇到了同样的问题。 解决方案非常简单,无需双重选择:

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”,因此所有行都是平局),或者如果没有结果,您将获得默认行。


4
投票

您可以使用完整的外部联接。一些效果......

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   

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


4
投票

这是@swe的答案,只是重新格式化:

CREATE FUNCTION [mail].[f_GetRecipients]
(
    @MailContentCode VARCHAR(50)
)
RETURNS TABLE
AS
RETURN
(
    SELECT TOP 1 WITH TIES -- Returns either all Priority 1 rows or, if none exist, all Priority 2 rows
        [To],
        CC,
        BCC
    FROM (
        SELECT
            [To],
            CC,
            BCC,
            1 AS Priority
        FROM mail.Recipients
        WHERE 1 = 1
            AND IsActive = 1
            AND MailContentCode = @MailContentCode

        UNION ALL

        SELECT
            *,
            2 AS Priority
        FROM (VALUES
            (N'[email protected]', NULL, NULL),
            (N'[email protected]', NULL, NULL)
        ) defaults([To], CC, BCC)
    ) emails
    ORDER BY Priority
)

1
投票

我想你可以尝试:

Declare @count int
set @count = 0

Begin
Select @count = Count([Column])
From //Your query

if(@Count = 0) 
   select 0
else //run your query

缺点是您实际上运行了两次查询,优点是您跳过了临时表。


1
投票

为了避免重复选择查询,先用一个临时表来存储查询结果怎么样?并基于临时表,如果临时表为空则返回默认行,或者当有结果时返回临时?


0
投票

查询虚拟行并使用左连接。

假设您有以下疑问:

mydb=> SELECT 1 AS a, 2 AS b;
 a | b 
---+---
 1 | 2
(1 row)

mydb=> SELECT 1 AS a, 2 AS b WHERE false;
 a | b 
---+---
(0 rows)

你总是想要 1 行。

您可以在 1 行占位符上使用左连接。这可以表示为连接或 CTE。

mydb=> SELECT coalesce(q.a, 0) AS a, q.b
       FROM (VALUES (NULL)) AS dummy_row
       LEFT OUTER JOIN (
         SELECT 1 AS a, 2 AS b
       ) AS q ON (true);
 a | b 
---+---
 1 | 2
(1 row)

mydb=> SELECT coalesce(q.a, 0) AS a, q.b FROM
       (VALUES (NULL)) AS dummy_row
       LEFT OUTER JOIN (
         SELECT 1 AS a, 2 AS b WHERE false
       ) AS q ON (true);
 a | b 
---+---
 0 |  
(1 row)

这是使用

VALUES (NULL)
提供占位符行的子查询公式。这是基于 CTE 的拼写,用
generate_series
代替:

mydb=> WITH q AS (SELECT 1 AS a, 2 AS b WHERE false)
       SELECT coalesce(q.a, 0) AS a, q.b FROM generate_series(1,1) x left join q on (true);
 a | b 
---+---
 0 |  
(1 row)

哎呀,postgres 拼写,不是 MS-SQL。同样的原则也应该适用。稍后我会修复它。

© www.soinside.com 2019 - 2024. All rights reserved.