Чи можу я вказати за замовчуванням для лівого зовнішнього з'єднання?


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 тут не працюватиме, тому що я не хочу, щоб значення за замовчуванням переосмислювало потенційні NULL в b2, де є значення b1, відповідне a1.

Тобто, з a і b як

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 NULL на виході. Це взагалі найкращий варіант, чи існує більш стандартний і акуратний спосіб?

Відповіді:


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 NULL на виході. Це найкращий варіант взагалі чи є більш стандартний і акуратний спосіб?"
Том Елліс

3
оскільки ви хочете розрізняти NULL, які виникають через ПРИЄДНУЮТЬСЯ, і ті, які "природно" присутні, неминуче вам доведеться вивчити 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);

Це повністю спрацює та створить саме те, що ви хочете.

Використання підвідбору

Не використовуйте цей метод, це ідея нарощування. Продовжуйте читати.

Якщо у нас немає жодних 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. Тут ми перевіряємо, чи не вказано це значення ROW. Це працюватиме так довго, як і кожен стовпець 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 дуже корисною у цьому випадку. Він поверне перше не NULL значення зі списку:

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.