Добавьте пустую строку в результаты запроса, если результаты не найдены


Я пишу хранимые procs, которые вызываются устаревшей системой. Одно из ограничений устаревшей системы заключается в том, что в одном результирующем наборе, возвращаемом из сохраненного процесса, должна быть по крайней мере одна строка. Стандарт состоит в том, чтобы вернуть ноль в первом столбце (да, я знаю!).

Очевидный способ достичь этого-создать временную таблицу, поместить в нее результаты, проверить все строки В временной таблице и либо вернуть результаты из временной таблицы, либо один пустой результат.

Другой способ может заключаться в том, чтобы сделать EXISTS против того же предложения where, которое находится в основном запросе до выполнения основного запроса.

Ни то, ни другое не приносит большого удовлетворения. Может ли кто-нибудь придумать лучший способ. Я думал о таких союзах, как этот (я знаю, что это не работает):
--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
6 20

6 ответов:

Это старый вопрос, но у меня была та же проблема. Решение действительно простое без двойного выбора:

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", поэтому все являются связями), или если нет результата, вы получаете свой defaultrow.

Боюсь, что вариантов очень мало.

Вы всегда должны коснуться таблицы дважды, будь то COUNT, EXISTS before, EXISTs in UNION, TOP clause и т. д.

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)

Существующее решение лучше, чем считать, потому что оно остановится, когда найдет строку. Подсчет будет проходить все строки, чтобы их сосчитать

Вы можете использовать полное внешнее соединение. Что-то в этом роде...

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   

В настоящее время я сам тестирую этот сценарий, поэтому не уверен, какое влияние это окажет, но это даст вам пустую строку с заполненной категорией.

Это ответ @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
)

Я думаю, вы могли бы попробовать:

Declare @count int
set @count = 0

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

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

Недостатком является то, что вы эффективно выполняете запрос дважды, а недостатком является то, что вы пропускаете временную таблицу.

Чтобы избежать дублирования запроса выбора, как насчет временной таблицы для хранения результата запроса в первую очередь? И на основе временной таблицы, возвращать строку по умолчанию, если временная таблица пуста или возвращать временную, когда она имеет результат?