2010-07-29 3 views
17

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

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

Другим способом может быть выполнение 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 
+1

Рассмотрите принятый ответ после прочтения решения @ swe! Это так хорошо, я признаю, что я почувствовал желание высунуть вас сюда;) http: // stackoverflow.com/a/32586119/2979473 – ensisNoctis

+0

@ensisNoctis, если я не очень ошибаюсь, это решение будет работать только в ситуациях, когда вы ожидаете либо нулевой, либо один результат назад –

+1

К счастью, вы - позвольте мне поделиться с вами этим кодом, который в настоящее время в производстве в моей компании, все благодаря StackOverflow;) Не мог вместить все это в этот комментарий, поэтому я опубликовал другой ответ, но он все еще @ swe, только отформатирован лучше. http://stackoverflow.com/a/37046650/2979473 Он возвращает строки из нужной таблицы, если они существуют (любое число> = 1), в противном случае строки из другой таблицы (или литералы, как в моем примере). – ensisNoctis

ответ

10

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

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

самых «С СВЯЗЯМИ» вы получите все строки (все они имеют 1, как «orderdummy», поэтому все связи), или, если нет никакого результата, вы получите свое недоразвитие.

+0

Это потрясающе! Простой, быстрый и способ лучше, чем принятый ответ, поскольку он не использует временные таблицы, не выполняет двойных запросов и не объявляет переменные (поэтому их можно легко использовать в встроенных TVF)! – ensisNoctis

0

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

Declare @count int 
set @count = 0 

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

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

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

+0

Это аналогичный метод для выражения EXISTS, которое я предложил в вопросе. Разница в том, что счет немного менее эффективен. –

27

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

Вы всегда должны касаться стола в два раза, то ли COUNT, СУЩЕСТВУЕТ раньше, EXISTS в 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) 

СУЩЕСТВУЕТ решение лучше, чем COUNT, потому что он остановится, когда он находит строку. COUNT будет пересекать все строки, чтобы на самом деле считать их

+0

Появилась новая информация для меня: EXISTS останавливается, когда находит строку. Спасибо @gbn! –

+0

+1: My WITH/TOP не смог вернуть фиктивную строку, когда у WITH нет данных. –

+0

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

2

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

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 

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

+0

Это действительно интересное решение, позволяющее дважды записывать предложение where. Мне было бы интересно узнать, работает ли это и какова стоимость исполнения? Я не могу понять, почему вы завершаете основной запрос в производной таблице. Это необходимо? –

+0

Основная оболочка запроса связана с предложением where, но может быть переписана в зависимости от того, как вы структурируете базовый запрос. Это вы не присоединяетесь к правильной области (постфильтрация), тогда критерии применимы к обеим таблицам. Расходы кажутся минимальными (0% в фактическом плане выполнения), однако у меня есть довольно сложный запрос. –

+0

Да, это имеет смысл теперь, когда вы включили isnull. Спасибо –

0

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

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'[email protected]', NULL, NULL, 2), 
      (N'[email protected]', NULL, NULL, 2) 
     ) defaults([To], CC, BCC, Priority) 
    ) emails 
    ORDER BY Priority 
) 
Смежные вопросы