2009-05-07 34 views
19

Tôi muốn tạo một danh sách ký tự của tất cả các chữ cái đầu tiên của cột trong cơ sở dữ liệu của tôi. SQL dưới đây không đúng những gì tôi muốn quay trở lại.Trả lại ký tự đầu tiên DISTINCT của một trường (MySQL)

 
SELECT DISTINCT first_character(name) FROM mydatabase 

Có cách nào để thực hiện việc này trong MySQL không?

EDIT Lợi thế của việc sử dụng SUBSTRING trên LEFT và ngược lại là gì?

EDIT Hiện tại có khoảng 1700 bản ghi trong bảng và đang phát triển.

+1

Bạn có bao nhiêu bản ghi trong bảng?Tôi muốn đăng một phiên bản được tối ưu hóa nhưng không biết liệu có bận tâm không :) – Quassnoi

+0

OK, tôi đã đăng nó :) Có lẽ ngày mai tôi sẽ đăng một bài đăng trong blog của tôi ra khỏi câu hỏi của bạn. – Quassnoi

Trả lời

55

Xin lỗi vì đã làm điều này, nhưng tôi đã tìm ra chính xác những gì tôi cần phải làm ngay bây giờ.

 
SELECT DISTINCT LEFT(name, 1) FROM mydatabase 

Điều này trả về danh sách ký tự đầu tiên, riêng biệt, mỗi hàng trong cột bắt đầu bằng. Tôi đã thêm nó vào danh sách theo thứ tự alpha-số:

 
SELECT DISTINCT LEFT(name, 1) as letter FROM mydatabase ORDER BY letter 

Làm việc như một sự quyến rũ.

+0

Hoàn toàn có thể chấp nhận để đăng câu trả lời cho câu hỏi của riêng bạn. +1 –

+0

Tôi sử dụng 'SUBSTRING()' vì nó là một tiêu chuẩn SQL. Tôi đã không tìm thấy một tiêu chuẩn cho hàm 'LEFT()'. http://troels.arvin.dk/db/rdbms/#functions-SUBSTRING – Sonny

9

Âm thanh đơn giản:

select distinct substring(field,1,1) as char 
from mytable 
+1

Sử dụng chuẩn SQL: 'SUBSTRING (đầu vào FROM vị trí bắt đầu [FOR length])' -> 'SUBSTRING (trường FROM 1 FOR 1)' – Sonny

+0

@Sonny: Cú pháp không chính xác gần từ khóa 'FROM'. – Andomar

+0

Tôi không chắc tại sao bạn nói "Cú pháp sai" cú pháp tôi đăng được hiển thị ở đây: http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_substring - Truy vấn đầy đủ sẽ là điều này: 'SELECT DISTINCT SUBSTRING (trường FROM 1 FOR 1) AS char FROM mytable' – Sonny

9

Đối với bảng hiện tại của 1,700 hàng, giải pháp của bạn là OK.

Nếu bạn sẽ có số 100,000 hàng, DISTINCT có thể trở nên không hiệu quả.

Dưới đây là bài viết trong blog của tôi cho thấy làm thế nào để làm điều đó một cách hiệu quả:

Giải pháp này sử dụng một chỉ mục trên name. Nó sẽ nhảy qua các phím chỉ mục, chọn từng chữ cái đầu tiên nhiều nhất một lần.

Trước tiên, bạn sẽ cần phải tạo một hàm:

CREATE FUNCTION fn_get_next_code(initial INT) RETURNS INT 
NOT DETERMINISTIC 
READS SQL DATA 
BEGIN 
     DECLARE _next VARCHAR(200); 
     DECLARE EXIT HANDLER FOR NOT FOUND RETURN NULL; 
     SELECT ORD(SUBSTRING(name, 1, 1)) 
     INTO _next 
     FROM t_names 
     WHERE name >= CHAR(initial + 1) 
     ORDER BY 
       name 
     LIMIT 1; 
     RETURN _next; 
END 

Chức năng này, được đưa ra một bộ quy tắc thư bắt đầu, trả về thư xuất phát đầu tiên bên cạnh đưa từ bảng.

Thứ hai, sử dụng chức năng này trong một truy vấn:

SELECT CHAR(@r) AS starting, 
     @r := fn_get_next_letter(@r) AS next 
FROM (
     SELECT @r := ORD(LEFT(MIN(name), 1)) 
     ) vars, mytable 
WHERE @r IS NOT NULL 

Trên mỗi lần lặp, phiên biến @r sẽ bỏ qua để lá thư bắt đầu tiếp theo sử dụng một chỉ mục.

Điều này sẽ rất nhanh, nhưng nó chỉ trả tiền nếu bạn có hàng trăm nghìn hàng.

Nếu không, chỉ sử dụng DISTINCT.

+0

+1, được đánh dấu khi tôi phải truy vấn bảng Liên Hợp Quốc của tất cả các thực thể được đặt tên trong vũ trụ: D – Andomar

+0

Đảm bảo rằng nó nằm trong US ASCII, không thử nghiệm trên Unicode :) – Quassnoi

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