Bắt CHỌN để trả về giá trị không đổi ngay cả khi hàng không khớp


15

Xem xét tuyên bố chọn này:

SELECT *, 
       1 AS query_id 
FROM players 
WHERE username='foobar';

Nó trả về cột query_idcó giá trị 1cùng với các cột khác của người chơi.

Làm sao người ta có thể làm cho sự trở lại SQL trên ít nhất là query_idcủa 1ngay cả khi phát hiện chọn không có hàng mà trận đấu?

BTW, đó là PostgreSQL 8.4.

Câu trả lời:


22
SELECT col1, 
       col2, 
       col3, 
       1 AS query_id 
FROM players 
WHERE username='foobar'
union all 
select null,
       null,
       null,
       1
where not exists (select 1 from players where username = 'foobar');

Hoặc như một giải pháp thay thế ( thể nhanh hơn vì không yêu cầu phụ thứ hai):

with qid (query_id) as (
   values (1)
) 
select p.*, 
       qid.query_id
from qid 
  left join players as p on (p.useranme = 'foobar');

Bạn có thể viết lại phần trên thành một bản trình bày "nhỏ gọn" hơn:

select p.*, 
       qid.query_id
from (values (1)) as qid (query_id)
  left join players as p on (p.useranme = 'foobar');

Nhưng tôi nghĩ rằng CTE ( with...) rõ ràng dễ đọc hơn (mặc dù điều đó luôn nằm trong mắt của kẻ si tình).


1
Khi thử ví dụ đầu tiên, có vẻ như TẤT CẢ từ khóa là không cần thiết?
Nathanael Weiss

2
@Natweiss: nếu bạn cần một đơn đặt hàng cụ thể, bạn phải cung cấp một order by. Bảng thứ hai "tạo" một bảng ảo với chính xác một hàng và một cột và thực hiện nối bên ngoài nó (không có bất kỳ điều kiện nối "thực" nào), do đó bạn luôn lấy lại ít nhất một hàng đó. Sử dụng select *trong mã sản xuất là phong cách xấu. Đừng làm điều đó. Luôn liệt kê các cột bạn cần. chỉselect * nên được sử dụng trong các truy vấn đặc biệt.
a_horse_with_no_name

2
@Natweiss: "cú pháp thay thế" nào cho "các phép nối khác" mà bạn đang đề cập đến. Và tại sao bạn nghĩ left joinlà không thể đọc được?
a_horse_with_no_name

2
@Natweiss: tham gia ngầm định trong mệnh đề where là kiểu mã hóa xấu và nên tránh. Nó có thể dẫn đến các cartesian không mong muốn tham gia mà không gây ra lỗi cho bạn. Và nó phân tách rõ ràng hai khái niệm (quan hệ) về nối và lọc
a_horse_with_no_name

4
re: không cần phải sửa đổi "tất cả" của mệnh đề "union": UNION ALLđôi khi có thể hiệu quả hơn UNION, vì bạn đang nói rõ ràng với người lập kế hoạch truy vấn rằng bạn sẽ không có hàng trùng lặp nào xuất hiện trong các UNIONtruy vấn ed hoặc nếu có bạn muốn chúng là đầu ra. Nếu không có công cụ ALLsửa đổi, nó giả sử bạn muốn loại bỏ các hàng trùng lặp (chỉ một trong số mỗi hàng được trả về) giống như với DISTINCTtừ khóa và để đảm bảo rằng nó có thể cần phải dùng đến + quét lại kết quả thêm thời gian. Vì vậy, sử dụng ALLvới UNIONtrừ khi bạn đặc biệt cần sao chép hàng đầu ra.
David Spillett

7

Nếu bạn chỉ mong đợi một hoặc không hàng trở lại, thì điều này cũng sẽ hoạt động:

SELECT
  max(col1) col1,
  max(col2) col2, 
  1 AS query_id 
FROM
  players 
WHERE
  username='foobar';

Điều này sẽ trả về một hàng với tất cả các giá trị có null ngoại trừ query_id nếu không tìm thấy hàng nào.


2
Bí quyết đẹp. Hạn chế duy nhất là các giá trị cho col1 và col2 có thể không thuộc cùng một hàng, nếu có nhiều hơn một điều kiện khớp với điều kiệnusername = 'foobar'
a_horse_with_no_name

1
Coalesce () cũng có thể được sử dụng trong thời trang này?
Nathanael Weiss

1
Coalesce sẽ không tạo ra một hàng trong đó không có hàng nào được chiếu từ bảng.
David Aldridge

1
@a_horse_with_no_name có, mặc dù tên bảng và cột cho thấy vị từ nằm trên khóa ứng cử viên cho bảng, do đó, không hoặc một hàng nào sẽ được chiếu.
David Aldridge

3

Đi lang thang muộn ở đây, nhưng đây là một cú pháp hoạt động (ít nhất là trong 9.2, chưa thử các phiên bản trước đó).

SELECT (COALESCE(a.*,b.*::players)).*
FROM ( SELECT col1,  col2,  col3, 1 AS query_id 
       FROM players WHERE username='foobar' ) a
RIGHT JOIN (select null col1, null col2, null col3, 1 col4) b
ON a.query_id = b.col4;

Sẽ chỉ trả về hàng "trống" nếu toàn bộ nội dung của "a" là null.

Thưởng thức. / bithead


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.