2016-01-07 27 views
7

Tôi không phải là tốt nhất trong SQL rất tiếc nếu tôi đặt câu hỏi ngu ngốc :)SQL - điều kiện đệ quy trong mệnh đề SELECT

Hãy có một bảng như thế này:

|id| name | nickname | 
|==|========|============| 
| 1|  Jo|  Banana| 
| 2|Margaret|The Princess| 
| 3| Perry| The Monkey| 
| 4|Margaret| The Queen| 
| 5|  |  The Rat| 
| 6|  |  The Cat| 

nơi nickname luôn là độc nhất.

Và tôi đang cố gắng để có được kết quả như thế này:

|id| name | nickname |  display_name  | 
|==|========|============|=======================| 
| 1|  Jo|  Banana|      Jo| 
| 2|Margaret|The Princess|Margaret (The Princess) 
| 3| Perry| The Monkey|     Perry| 
| 4|Margaret| The Queen| Margaret (The Queen)| 
| 5|  |  The Rat|    The Rat| 
| 6|  |  The Cat|    The Cat| 

Về cơ bản logic là:

  1. Nếu nametrống sau đó display_name = 'nickname'
  2. Nếu nameđộc đáo sau đó display_name = 'name'
  3. Nếu namenot_unique sau đó display_name = 'name (nickname)'

Tôi có thể đạt được điều đó chỉ với một truy vấn SQL? Nếu vậy - làm thế nào? Nếu không - các lựa chọn thay thế là gì?

Hiện tại tôi làm điều đó bằng ngôn ngữ lập trình nhưng tôi phải gửi cho mỗi hàng kết quả truy vấn SQL khác để kiểm tra xem có các bản ghi khác có cùng tên OK cho kết quả được lọc hay không, nhưng quá tham lam khi truy xuất toàn bộ bảng (4 000 hàng và tăng trưởng).

Trả lời

7

Bạn có thể sử dụng phiên bản chức năng cửa sổ của COUNT() để xác định xem name cho một hàng nhất định là độc đáo mà không thực hiện một subquery. Ví dụ:

SELECT 
    id, name, nickname, 
    CASE 
    WHEN ISNULL(name, '') = '' THEN nickname 
    WHEN (COUNT(*) OVER (PARTITION BY name)) = 1 THEN name 
    ELSE name + ' (' + nickname + ')' 
    END AS display_name 
FROM my_table 
+0

Hi @ john-bollinger, cảm ơn bạn đã trả lời. Hai câu hỏi chỉ xuất hiện trong tâm trí của tôi: 1) Lệnh 'OVER (PARTITION BY)' chỉ dành cho 'sqlserver'? 2) Tại sao 'row_number' sẽ không hoạt động? Cảm ơn –

+0

@AndyK, mệnh đề 'OVER()' là những gì làm cho 'COUNT()' một hàm cửa sổ thay vì hàm tổng hợp. Đây là các tính năng SQL tiêu chuẩn kể từ SQL2003, được mở rộng trong SQL2008. Nhiều cơ sở dữ liệu SQL khác với SQL Server thực hiện chúng (Oracle và PostgreSQL là hai trong số nhiều), nhưng không phải tất cả (MySQL là một trong những ngoại lệ nổi bật hơn). –

+0

@AndyK, hàm 'ROW_NUMBER()' trả về số thứ tự của hàng hiện tại liên quan đến phân vùng và/hoặc thứ tự được xác định bởi mệnh đề 'OVER()'. Điều đó cho phép bạn nhận ra các hàng thứ hai và tiếp theo của bất kỳ phân vùng nào thuộc về một phân vùng có nhiều hơn một hàng, nhưng khi số hàng là '1' bạn không biết liệu có bất kỳ hàng tiếp theo nào trong phân đoạn của hàng đó hay không. –

2

Bạn có thể thử này -

SELECT 
    * 
    ,display_name = 
        CASE 
         WHEN (ROW_NUMBER() OVER (PARTITION BY name ORDER BY id) = 1) THEN name 
         WHEN ISNULL(name, '') = '' THEN nickname 
         ELSE name + ' (' + nickname + ')' 
        END 
FROM MyTable 
+0

Hi @ krishnraj-rana, giải pháp của bạn có vẻ rất thanh lịch ... –

+1

Một chức năng cửa sổ là một cách tốt để đi, nhưng 'ROW_NUMBER()' là một sai cho công việc này. Việc sử dụng cụ thể này sẽ tạo ra kết quả sai cho hàng '-' thấp nhất trong mỗi nhóm có cùng giá trị' tên'. –

+0

@JohnBollinger: Bạn nói đúng ... Tôi đã sửa đổi câu trả lời của tôi. Cảm ơn bạn đã chỉ ra. –

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