2012-11-04 40 views
20

phép nói rằng tôi có một cơ sở dữ liệu SQLite có chứa một bảng:Tại sao CHỌN 0, ... thay vì CHỌN

sqlite> create table person (id integer, firstname varchar, lastname varchar); 

Bây giờ tôi muốn để có được tất cả các mục mà là trong bảng.

sqlite> select t0.id, t0.firstname, t0.lastname from person t0; 

Điều này làm việc tốt và điều này tôi sẽ sử dụng. Tuy nhiên tôi đã làm việc với một khuôn khổ từ Apple (Core Data) tạo ra SQL. Khung công tác này tạo ra một truy vấn SQL hơi khác:

sqlite> select 0, t0.id, t0.firstname, t0.lastname from person t0; 

Mọi truy vấn SQL được tạo bởi khung này bắt đầu bằng "chọn 0". Tại sao vậy?

Tôi đã cố gắng sử dụng lệnh giải thích để xem điều gì đang xảy ra nhưng điều này không thuyết phục - ít nhất là với tôi.

sqlite> explain select t0.id, t0.firstname, t0.lastname from person t0; 
addr  opcode  p1   p2   p3   p4   p5   comment 
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- 
0   Trace  0   0   0      00   NULL  
1   Goto  0   11   0      00   NULL  
2   OpenRead 0   2   0   3   00   NULL  
3   Rewind  0   9   0      00   NULL  
4   Column  0   0   1      00   NULL  
5   Column  0   1   2      00   NULL  
6   Column  0   2   3      00   NULL  
7   ResultRow 1   3   0      00   NULL  
8   Next  0   4   0      01   NULL  
9   Close  0   0   0      00   NULL  
10   Halt  0   0   0      00   NULL  
11   Transactio 0   0   0      00   NULL  
12   VerifyCook 0   1   0      00   NULL  
13   TableLock 0   2   0   person  00   NULL  
14   Goto  0   2   0      00   NULL 

Và bảng cho truy vấn thứ hai trông như thế này:

sqlite> explain select 0, t0.id, t0.firstname, t0.lastname from person t0; 
addr  opcode  p1   p2   p3   p4   p5   comment 
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- 
0   Trace  0   0   0      00   NULL  
1   Goto  0   12   0      00   NULL  
2   OpenRead 0   2   0   3   00   NULL  
3   Rewind  0   10   0      00   NULL  
4   Integer  0   1   0      00   NULL  
5   Column  0   0   2      00   NULL  
6   Column  0   1   3      00   NULL  
7   Column  0   2   4      00   NULL  
8   ResultRow 1   4   0      00   NULL  
9   Next  0   4   0      01   NULL  
10   Close  0   0   0      00   NULL  
11   Halt  0   0   0      00   NULL  
12   Transactio 0   0   0      00   NULL  
13   VerifyCook 0   1   0      00   NULL  
14   TableLock 0   2   0   person  00   NULL  
15   Goto  0   2   0      00   NULL  

Trả lời

15

Một số khuôn khổ thực hiện điều này để nói, không chút nghi ngờ, cho dù một dòng từ bảng đã được trả lại.

Cân nhắc

A  B 
+---+ +---+------+ 
| a | | a | b | 
+---+ +---+------+ 
| 0 | | 0 | 1 | 
+---+ +---+------+ 
| 1 | | 1 | NULL | 
+---+ +---+------+ 
| 2 | 
+---+ 

SELECT A.a, B.b 
FROM A 
LEFT JOIN B 
ON B.a = A.a 

    Results 
+---+------+ 
| a | b | 
+---+------+ 
| 0 | 1 | 
+---+------+ 
| 1 | NULL | 
+---+------+ 
| 2 | NULL | 
+---+------+ 

Trong tập kết quả này, nó không phải là có thể thấy rằng a = 1 tồn tại trong bảng B, nhưng a = 2 không. Để có được thông tin đó, bạn cần phải chọn một biểu thức không nullable từ bảng b, và cách đơn giản nhất để làm điều đó là chọn một giá trị hằng số đơn giản.

SELECT A.a, B.x, B.b 
FROM A 
LEFT JOIN (SELECT 0 AS x, B.a, B.b FROM B) AS B 
ON B.a = A.a 

    Results 
+---+------+------+ 
| a | x | b | 
+---+------+------+ 
| 0 | 0 | 1 | 
+---+------+------+ 
| 1 | 0 | NULL | 
+---+------+------+ 
| 2 | NULL | NULL | 
+---+------+------+ 

Có rất nhiều tình huống mà những giá trị không đổi, không yêu cầu, ví dụ như khi bạn không có tham gia, hoặc khi bạn có thể chọn một cột nullable từ b thay vào đó, nhưng họ không gây ra bất kỳ tác hại nào, vì vậy chúng chỉ có thể được đưa vào vô điều kiện.

+0

Nhưng hằng '0' là * không * từ bảng B; nó được trả lại vô điều kiện trong mọi bản ghi kết quả. –

+0

@CL. Chỉnh sửa để làm cho nó rõ ràng hơn những gì tôi có ý nghĩa. – hvd

+0

Nhưng Dữ liệu cốt lõi đặt '0' vào truy vấn ngoài cùng. –

0

Chỉ của Apple biết ... nhưng tôi thấy hai khả năng:

  1. Chèn một cột giả đảm bảo rằng thực tế cột đầu ra được đánh số bắt đầu bằng 1, không phải 0. Nếu một số giao diện hiện đã giả one- dựa trên đánh số, làm theo cách này trong phần phụ trợ SQL có thể là giải pháp đơn giản nhất.

  2. Nếu bạn thực hiện một truy vấn cho nhiều đối tượng sử dụng nhiều truy vấn con, một giá trị như thế này có thể được sử dụng để xác định từ đó subquery một kỷ lục có nguồn gốc:

    SELECT 0, t0.firstname, ... FROM PERSON t0 WHERE t0.id = 123 
    UNION ALL 
    SELECT 1, t0.firstname, ... FROM PERSON t0 WHERE t0.id = 456 
    

    (Tôi không biết nếu Core Data thực thực hiện điều này.)


đầu ra EXPLAIN của bạn cho thấy rằng sự khác biệt duy nhất là (tại địa chỉ 4) rằng chương trình thứ hai đặt cột phụ để zero, s o chỉ có một sự khác biệt hiệu suất tối thiểu.

8

Khi tôi có mã để tự động tạo ra một khoản WHERE, tôi thường bắt đầu mệnh đề với:

WHERE 1 = 1 

Sau đó, vòng lặp để thêm điều kiện bổ sung luôn cho biết thêm mỗi điều kiện trong định dạng tương tự:

AND x = y 

mà không cần đặt logic điều kiện tại chỗ để kiểm tra xem đây có phải là điều kiện đầu tiên hay không: "nếu đây là điều kiện đầu tiên, hãy bắt đầu bằng từ khóa WHERE, hãy thêm từ khóa AND"

Vì vậy, tôi có thể tưởng tượng một khung làm việc này vì những lý do tương tự. Nếu bạn bắt đầu câu lệnh với một số SELECT 0 thì mã để thêm các cột tiếp theo có thể ở trong một vòng lặp mà không có bất kỳ câu lệnh có điều kiện nào. Chỉ cần thêm , colx mỗi lần mà không có bất kỳ kiểm tra có điều kiện nào dọc theo dòng "nếu đây là cột đầu tiên, không đặt dấu phẩy trước tên cột, nếu không thì".

Ví dụ mã giả:

String query = "SELECT 0"; 

for (Column col in columnList) 
    query += ", col"; 
+0

Tôi thấy quan điểm của bạn nhưng sau đó lại: Trong Mục tiêu-C, bạn có thể chỉ cần tham gia các tên cột như sau: [@ [@ "firstName", @ "lastName"] componentsJoinedByString: @ ","]]; Vì vậy, nếu không cần thiết ở đây. –

+0

Đó sẽ là chính xác loại mã tôi sẽ xem xét để tránh :) – Glenn

+0

Tôi sẽ thay vì sử dụng componentsJoinedByString thay vì một vòng lặp for. Có lẽ nó chỉ là vấn đề của hương vị ... :) –

Các vấn đề liên quan