Можете ли вы иметь логику if-then-else в SQL?

Мне нужно сделать выбор данных из таблицы на основе какого-то приоритета следующим образом:

select product, price from table1 where project = 1

-- pseudo: if no price found, do this:
select product, price from table1 where customer = 2

-- pseudo: if still no price found, do this:
select product, price from table1 where company = 3

То есть, если я нашел 3 продукта с ценами на основе project = X, я не хочу выбирать на customer = Y. Я просто хочу вернуть полученные 3 строки и сделать.

Как вы должны делать такие вещи в SQL? Используйте какой-то CASE-оператор для псевдо-if? Сделайте союз или какую-нибудь другую умную вещь?

Изменить: я использую MS SQL.

Спасибо!

Ответ 1

Вы можете сделать следующий SQL-запрос

IF ((SELECT COUNT(*) FROM table1 WHERE project = 1) > 0) 
    SELECT product, price FROM table1 WHERE project = 1
ELSE IF ((SELECT COUNT(*) FROM table1 WHERE project = 2) > 0) 
    SELECT product, price FROM table1 WHERE project = 2
ELSE IF ((SELECT COUNT(*) FROM table1 WHERE project = 3) > 0)
    SELECT product, price FROM table1 WHERE project = 3

Ответ 2

Оператор CASE является самым близким к оператору IF в SQL и поддерживается во всех версиях SQL Server:

SELECT CASE <variable> 
           WHEN <value>      THEN <returnvalue> 
           WHEN <othervalue> THEN <returnthis> 
           ELSE <returndefaultcase> 
       END 
  FROM <table> 

Ответ 3

Вместо использования EXISTS и COUNT просто используйте @@ROWCOUNT:

select product, price from table1 where project = 1

IF @@ROWCOUNT = 0
BEGIN
    select product, price from table1 where customer = 2

    IF @@ROWCOUNT = 0
    select product, price from table1 where company = 3
END

Ответ 4

Пожалуйста, проверьте, помогает ли это:

select TOP 1
    product, 
    price 
from 
    table1 
where 
    (project=1 OR Customer=2 OR company=3) AND
    price IS NOT NULL
ORDER BY company 

Ответ 5

С SQL-сервером вы можете просто использовать CTE вместо логики IF/THEN, чтобы упростить отображение ваших существующих запросов и изменение количества вовлеченных запросов;

WITH cte AS (
    SELECT product,price,1 a FROM table1 WHERE project=1   UNION ALL
    SELECT product,price,2 a FROM table1 WHERE customer=2  UNION ALL
    SELECT product,price,3 a FROM table1 WHERE company=3
)
SELECT TOP 1 WITH TIES product,price FROM cte ORDER BY a;

SQLfiddle для тестирования с.

В качестве альтернативы вы можете объединить все это в один SELECT, чтобы упростить его для оптимизатора;

SELECT TOP 1 WITH TIES product,price FROM table1 
WHERE project=1 OR customer=2 OR company=3
ORDER BY CASE WHEN project=1  THEN 1 
              WHEN customer=2 THEN 2
              WHEN company=3  THEN 3 END;

Еще один SQLfiddle.

Ответ 6

есть аргумент case, но я думаю, что ниже более точный/эффективный/более легкий для чтения для того, что вы хотите.

select 
  product
  ,coalesce(t4.price,t2.price, t3.price) as price
from table1 t1
left join table1 t2 on t1.product = t2.product and t2.customer =2
left join table1 t3 on t1.product = t3.product and t3.company =3
left join table1 t4 on t1.product = t4.product and t4.project =1

Ответ 7

- Подобный ответ, как указано выше, по большей части. Код, включенный для тестирования

DROP TABLE table1
GO
CREATE TABLE table1 (project int, customer int, company int, product int, price money)
GO
INSERT INTO table1 VALUES (1,0,50, 100, 40),(1,0,20, 200, 55),(1,10,30,300, 75),(2,10,30,300, 75)
GO
SELECT TOP 1 WITH TIES product
        , price
        , CASE WhereFound WHEN 1 THEN 'Project'
                WHEN 2 THEN 'Customer'
                WHEN 3 THEN 'Company'
            ELSE 'No Match'
            END AS Source
FROM 
    (
     SELECT product, price, 1 as WhereFound FROM table1 where project = 11
     UNION ALL
     SELECT product, price, 2 FROM table1 where customer = 0
     UNION ALL
     SELECT product, price, 3 FROM table1 where company = 30
    ) AS tbl
ORDER BY WhereFound ASC