Могу ли я указать значение по умолчанию для левого внешнего соединения?


21

Предположим, у меня есть таблицы a (со столбцом a1) и b (со столбцами b1 и b2), и я выполняю внешнее левое соединение

SELECT *
FROM a LEFT OUTER JOIN b
ON a.a1 = b.b1

Тогда b1 и b2 будут равны NULL, если значение a1 не соответствует значению b1.

Могу ли я указать значение по умолчанию для b2 вместо NULL? Обратите внимание , что COALESCE не будет работать здесь, потому что я не хочу , значение по умолчанию для переопределения потенциальных NULLs в b2 , где это значение b1 согласования a1.

То есть с а и б как

CREATE TABLE a (a1)
  AS VALUES (1),
            (2),
            (3) ;

CREATE TABLE b (b1,b2)
  AS VALUES (1, 10),
            (3, null) ;


a1     b1 | b2
---    --------
 1      1 | 10
 2      3 | NULL
 3

и по умолчанию для b2, скажем, 100, я хочу получить результат

a1 | b1   | b2
---------------
1  |  1   | 10
2  | NULL | 100
3  |  3   | NULL

В этом простом случае я мог бы сделать это «вручную», посмотрев, является ли b1 нулевым в выводе. Это лучший вариант в целом, или есть более стандартный и аккуратный способ?

Ответы:


23
SELECT a.a1,b.b1,  
    CASE WHEN b.b1 is NULL THEN 5 ELSE b.b2 END AS b2  
FROM a LEFT OUTER JOIN b  
ON a.a1 = b.b1

2
Пожалуйста, используйте ANSI SQL, когда вопрос помечен только sql(что означает «SQL язык запросов». Этот тег не обозначает какой-либо конкретный продукт или диалект СУБД). Часть: [b2]=CASE WHEN ... ENDявляется недопустимым (стандартным) выражением SQL.
a_horse_with_no_name

Я добавил тег, чтобы указать, что я приму конкретный ответ Postgres. Тем не менее, стандартный SQL предпочтительнее, если это возможно.
Том Эллис

@Kin: как указано в моем вопросе, я знаю, что "я мог бы сделать это" вручную ", посмотрев, является ли b1 нулевым в выводе. Это лучший вариант в целом, или есть более стандартный и аккуратный способ?"
Том Эллис

3
поскольку вы хотите различать значения NULL, возникающие из-за JOIN, и те, которые «естественно» присутствуют, вам неизбежно придется проверить b1. Если это то, что вы имели в виду под «я мог бы сделать это« вручную »», то да, это единственный способ.
Мордехай

@MorDeror: Ладно, я думаю, что мог подумать, что может быть такой синтаксис, как «СЛЕВАЯ ВНЕШНЕЕ СОЕДИНЕНИЕ ... ВКЛ ... ПО УМОЛЧАНИЮ b2 = ...».
Том Эллис

2

Первоначальный ответ на этот вопрос остался необъяснимым, поэтому давайте попробуем еще раз.

Используя CASEутверждение

Используя этот метод, мы используем другое значение в другом столбце, котороеIS NOT NULL в этом случае, b.b1если это значение равно нулю, мы знаем, что соединение не удалось.

SELECT
  a.a1,
  b.b1,  
  CASE WHEN b.b1 is NULL THEN 100 ELSE b.b2 END AS b2  
FROM a
LEFT OUTER JOIN b  
  ON (a.a1 = b.b1);

Это будет полностью работать и генерировать именно то, что вы хотите.

Использование sub-SELECT

Не используйте этот метод, это идея наращивания. Продолжай читать.

Если у нас нет каких-либо NOT NULLстолбцов, которые мы могли бы использовать таким образом, нам нужно что-то, чтобы создать столбец, который мог бы работать таким образом для нас ...

SELECT
  a.a1,
  b.b1,  
  CASE WHEN b.cond IS NULL THEN 100 ELSE b.b2 END AS b2  
FROM a
LEFT OUTER JOIN (
  SELECT true AS cond, b.*
  FROM b
) AS b
  ON (a.a1 = b.b1);

Использование сравнения строк

Еще проще, чем форсировать ложное значение, для которого мы можем сравнить, - сравнить строку. В PostgreSQL строка имеет значение по имени таблицы. Например, SELECT foo FROM fooвозвращает строку типа foo(которая является типом строки) из таблицы foo. Здесь мы проверяем, является ли эта строка нулевой. Это будет работать до тех пор, пока каждый столбец IS NOT NULL. И, если каждый столбец IS NULLв вашей таблице, то вы просто троллинг.

SELECT
  a.a1,
  b.b1,  
  CASE WHEN b IS NULL THEN 100 ELSE b.b2 END AS b2  
FROM a
LEFT OUTER JOIN b
  ON (a.a1 = b.b1);

Столбец, b1используемый в CASEрастворе, не должен быть необнуляемым. Строительство работает в любом случае.
ypercubeᵀᴹ

1

Я считаю, что в этом случае COALESCE будет очень полезен. Он вернет первое ненулевое значение из списка:

SELECT
 a.a1,
 b.b1,
 COALESCE (b.b2, 100) AS b2
FROM a
LEFT OUTER JOIN b
  ON (a.a1 = b.b1);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.