Как установить строку по умолчанию для запроса, который не возвращает строк? - PullRequest
28 голосов
/ 13 ноября 2008

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

Редактировать: это будет SQL Server.

Ответы [ 9 ]

33 голосов
/ 13 ноября 2008

Один подход для Oracle:

SELECT val
FROM myTable
UNION ALL
SELECT 'DEFAULT'
FROM dual
WHERE NOT EXISTS (SELECT * FROM myTable)

Или в Oracle:

SELECT NVL(MIN(val), 'DEFAULT')
FROM myTable

Или, альтернативно, в SqlServer:

SELECT ISNULL(MIN(val), 'DEFAULT')
FROM myTable

Они используют тот факт, что MIN() возвращает NULL, когда строк нет.

13 голосов
/ 13 ноября 2008

Если ваш базовый запрос должен возвращать только одну строку, то вы можете использовать этот трюк:

select NVL( MIN(rate), 0 ) AS rate 
from d_payment_index
where fy = 2007
  and payment_year = 2008
  and program_id = 18

(код Oracle, не уверен, что NVL - правильная функция для SQL Server.)

10 голосов
/ 13 ноября 2008

Это исключило бы выполнение запроса select дважды и улучшило бы производительность:

Declare @rate int

select 
    @rate = rate 
from 
    d_payment_index
where 
    fy = 2007
    and payment_year = 2008
    and program_id = 18

IF @@rowcount = 0
    Set @rate = 0

Select @rate 'rate'
6 голосов
/ 10 февраля 2009

Как насчет этого:

SELECT DEF.Rate, ACTUAL.Rate, COALESCE(ACTUAL.Rate, DEF.Rate) AS UseThisRate
FROM 
  (SELECT 0) DEF (Rate) -- This is your default rate
LEFT JOIN (
  select rate 
  from d_payment_index
  --WHERE 1=2   -- Uncomment this line to simulate a missing value

  --...HERE IF YOUR ACTUAL WHERE CLAUSE. Removed for testing purposes...
  --where fy = 2007
  -- and payment_year = 2008
  --  and program_id = 18
) ACTUAL (Rate) ON 1=1

Результаты

Действительная ставка существует

Rate        Rate        UseThisRate
----------- ----------- -----------
0           1           1

Используемая скорость по умолчанию

Rate        Rate        UseThisRate
----------- ----------- -----------
0           NULL        0

Тест DDL

CREATE TABLE d_payment_index (rate int NOT NULL)
INSERT INTO d_payment_index VALUES (1)
2 голосов
/ 13 ноября 2008

Один метод сканирования таблицы с использованием левого соединения от значений по умолчанию до фактических:

CREATE TABLE [stackoverflow-285666] (k int, val varchar(255))

INSERT  INTO [stackoverflow-285666]
VALUES  (1, '1-1')
INSERT  INTO [stackoverflow-285666]
VALUES  (1, '1-2')
INSERT  INTO [stackoverflow-285666]
VALUES  (1, '1-3')
INSERT  INTO [stackoverflow-285666]
VALUES  (2, '2-1')
INSERT  INTO [stackoverflow-285666]
VALUES  (2, '2-2')

DECLARE @k AS int
SET @k = 0

WHILE @k < 3
    BEGIN
        SELECT  @k AS k
               ,COALESCE(ActualValue, DefaultValue) AS [Value]
        FROM    (
                 SELECT 'DefaultValue' AS DefaultValue
                ) AS Defaults
        LEFT JOIN (
                   SELECT   val AS ActualValue
                   FROM     [stackoverflow-285666]
                   WHERE    k = @k
                  ) AS [Values]
                ON 1 = 1

        SET @k = @k + 1
    END

DROP TABLE [stackoverflow-285666]

Дает вывод:

k           Value
----------- ------------
0           DefaultValue

k           Value
----------- ------------
1           1-1
1           1-2
1           1-3

k           Value
----------- ------------
2           2-1
2           2-2
2 голосов
/ 13 ноября 2008

Я понял это, и оно должно работать и для других систем. Это вариант ответа WW.

select rate 
from d_payment_index
where fy = 2007
  and payment_year = 2008
  and program_id = 18
union
select 0 as rate 
from d_payment_index 
where not exists( select rate 
                  from d_payment_index
                  where fy = 2007
                    and payment_year = 2008
                    and program_id = 18 )
1 голос
/ 13 ноября 2008

Хотите вернуть полный ряд? Должна ли строка по умолчанию иметь значения по умолчанию или это может быть пустая строка? Вы хотите, чтобы строка по умолчанию имела ту же структуру столбцов, что и рассматриваемая таблица?

В зависимости от ваших требований, вы можете сделать что-то вроде этого:

1) запустить запрос и поместить результаты во временную таблицу (или табличную переменную) 2) проверьте, есть ли у временной таблицы результаты 3) если нет, верните пустую строку, выполнив оператор выбора, подобный этому (в SQL Server):

select '' as columnA, '' as columnB, '' as columnC from #tempTable

Где columnA, columnB и columnC - ваши фактические имена столбцов.

0 голосов
/ 03 июля 2018

В этом фрагменте используются общие табличные выражения для сокращения избыточного кода и улучшения читабельности. Это вариант ответа Джона Боугмана.

Синтаксис для SQL Server.

WITH products AS (
            SELECT prod_name,
                   price
              FROM Products_Table
             WHERE prod_name LIKE '%foo%'
     ),
     defaults AS (
            SELECT '-' AS prod_name,
                   0   AS price
     )

SELECT * FROM products
UNION ALL
SELECT * FROM defaults
 WHERE NOT EXISTS ( SELECT * FROM products );
0 голосов
/ 26 мая 2016

Вставьте значения по умолчанию в табличную переменную, затем обновите одну строку этого tableVar в соответствии с вашей фактической таблицей. Если строка найдена, tableVar будет обновлен; если нет, значение по умолчанию остается. Вернуть табличную переменную.

    ---=== The table & its data
    CREATE TABLE dbo.Rates (
        PkId int,
        name varchar(10),
        rate decimal(10,2)
    )
    INSERT INTO dbo.Rates(PkId, name, rate) VALUES (1, 'Schedule 1', 0.1)
    INSERT INTO dbo.Rates(PkId, name, rate) VALUES (2, 'Schedule 2', 0.2)

Вот решение:

---=== The solution 
CREATE PROCEDURE dbo.GetRate 
  @PkId int
AS
BEGIN
  DECLARE @tempTable TABLE (
    PkId int, 
    name varchar(10), 
    rate decimal(10,2)
 )

 --- [1] Insert default values into @tempTable. PkId=0 is dummy value  
 INSERT INTO @tempTable(PkId, name, rate) VALUES (0, 'DEFAULT', 0.00)

 --- [2] Update the single row in @tempTable with the actual value.
 ---     This only happens if a match is found
 UPDATE @tempTable
    SET t.PkId=x.PkId, t.name=x.name, t.rate = x.rate
    FROM @tempTable t INNER JOIN dbo.Rates x
    ON t.PkId = 0
    WHERE x.PkId = @PkId

 SELECT * FROM @tempTable
END

Проверьте код:

EXEC dbo.GetRate @PkId=1     --- returns values for PkId=1
EXEC dbo.GetRate @PkId=12314 --- returns default values
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...