Tôi có thể cung cấp một mặc định cho một tham gia bên ngoài bên trái?


21

Giả sử tôi có các bảng a (với cột a1) và b (với các cột b1 và b2) và tôi thực hiện nối ngoài bên trái

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

Khi đó b1 và b2 sẽ là NULL trong đó giá trị của a1 không có giá trị khớp với b1.

Tôi có thể cung cấp giá trị mặc định cho b2, thay vì NULL không? Lưu ý rằng liên hiệp sẽ không làm việc ở đây, bởi vì tôi không muốn các giá trị mặc định để ghi đè NULLs tiềm năng trong b2, nơi có một giá trị của a1 khớp b1.

Đó là, với a và b là

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

và mặc định cho b2 của, giả sử, 100, tôi muốn nhận kết quả

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

Trong trường hợp đơn giản này, tôi có thể thực hiện "bằng tay" bằng cách xem liệu b1 có phải là NULL trong đầu ra không. Đó có phải là lựa chọn tốt nhất nói chung, hoặc có một cách chuẩn hơn và gọn gàng hơn?

Câu trả lời:


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
Vui lòng sử dụng ANSI SQL khi câu hỏi chỉ được gắn thẻ sql(có nghĩa là "SQL ngôn ngữ truy vấn". Thẻ đó không biểu thị bất kỳ sản phẩm hoặc phương ngữ DBMS cụ thể nào). Phần: [b2]=CASE WHEN ... ENDlà một biểu thức SQL (tiêu chuẩn) không hợp lệ.
a_horse_with_no_name

Tôi đã thêm một thẻ để cho biết tôi sẽ chấp nhận câu trả lời cụ thể của Postgres. Tuy nhiên, SQL tiêu chuẩn sẽ được ưu tiên nếu có thể.
Tom Ellis

@Kin: như đã nêu trong câu hỏi của tôi, tôi biết rằng "Tôi có thể làm điều đó" bằng tay "bằng cách xem liệu b1 có phải là NULL trong đầu ra không. Đó có phải là lựa chọn tốt nhất nói chung, hoặc có cách nào chuẩn hơn và gọn gàng hơn không?"
Tom Ellis

3
vì bạn muốn phân biệt giữa các NULL xảy ra do THAM GIA và những người có mặt "tự nhiên", nên bạn phải kiểm tra b1 là điều không thể tránh khỏi. Nếu đó là những gì bạn có nghĩa là "Tôi có thể làm điều đó" bằng tay "", thì đúng hơn, đó là cách duy nhất.
Mordechai

@MorDeror: OK, tôi cho rằng tôi đã nghĩ rằng có thể có một cú pháp như "LEFT OUTER THAM GIA ... TRÊN ... DEFAULT b2 = ...".
Tom Ellis

2

Câu trả lời ban đầu cho câu hỏi này không giải thích được, vì vậy hãy đưa ra một cú đánh khác.

Sử dụng một CASEtuyên bố

Sử dụng phương pháp này, chúng tôi khai thác rằng chúng tôi có một giá trị khác trong một cột khác màIS NOT NULL trong trường hợp này b.b1nếu giá trị đó là null thì chúng tôi biết rằng việc nối không thành công.

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);

Điều này sẽ hoàn toàn hoạt động, và tạo ra điều chính xác mà bạn muốn.

Sử dụng một CHỌN phụ

Đừng sử dụng phương pháp này, đó là ý tưởng xây dựng. Hãy đọc tiếp.

Nếu chúng ta không có bất kỳ NOT NULLcột nào mà chúng ta có thể khai thác như vậy, chúng ta cần một cái gì đó để tạo một cột có thể hoạt động theo cách đó cho chúng ta ...

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);

Sử dụng so sánh hàng

Thậm chí dễ dàng hơn sau đó buộc một giá trị sai mà chúng ta có thể so sánh, là so sánh hàng. Trong PostgreSQL, hàng có một giá trị theo tên của bảng. Chẳng hạn, SELECT foo FROM footrả về một hàng kiểu foo(là loại hàng), từ bảng foo. Ở đây chúng tôi kiểm tra xem ROW đó có phải là null không. Điều này sẽ làm việc miễn là mỗi cột IS NOT NULL. Và, nếu mỗi cột IS NULLtrong bảng của bạn, thì bạn chỉ đang troll.

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);

Cột b1được sử dụng trong CASEgiải pháp không cần phải là nullable. Các công trình xây dựng trong cả hai trường hợp.
ypercubeᵀᴹ

1

Tôi thấy COALESCE rất hữu ích trong trường hợp đó. Nó sẽ trả về giá trị không NULL đầu tiên từ danh sách:

SELECT
 a.a1,
 b.b1,
 COALESCE (b.b2, 100) AS b2
FROM a
LEFT OUTER JOIN b
  ON (a.a1 = b.b1);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.