2016-01-07 75 views
7

我不是在SQL最好很抱歉,如果我問愚蠢的問題:)SQL - 在SELECT子句遞歸條件

讓我們像這樣的表:

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

其中nickname總是獨特。

和我想要得到的結果是這樣的:

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

基本上邏輯是:

  1. 如果name然後display_name = 'nickname'
  2. 如果name獨特那麼display_name = 'name'
  3. 如果namenot_unique然後display_name = 'name (nickname)'

可我只有一個SQL查詢的實現呢?如果是這樣 - 如何?如果不是 - 有哪些選擇?

目前我用我的編程語言來做,但我必須爲結果的每一行發送另一個SQL查詢,以檢查是否有其他記錄具有相同的名稱,對於過濾結果是可以的,但在檢索時過於貪婪整個桌子(4 000行和成長)。

回答

7

您可以使用COUNT()窗口功能版本,以確定name對於給定的行是否是不執行的子查詢是唯一的。例如:

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

嗨@ john-bollinger,非常感謝您的回答。有兩個問題突然出現在我腦海裏:1)'OVER(PARTITION BY)'命令僅適用於'sqlserver'? 2)爲什麼'row_number'不起作用?謝謝 –

+0

@AndyK,'OVER()'子句是使COUNT()成爲窗口函數而不是聚合函數的原因。這些是自SQL2003以來的標準SQL功能,在SQL2008中進行了擴展。除了SQL Server之外,許多SQL數據庫都實現它們(Oracle和PostgreSQL只是其中的兩個),但並非都是這樣做的(MySQL是更顯着的例外之一)。 –

+0

@AndyK,'ROW_NUMBER()'函數返回當前行相對於OVER()'子句定義的分區和/或順序的序號。這允許您將任何分區的第二行和後續行識別爲屬於具有多行的分區,但行號爲1時,您不知道該行分區中是否存在任何後續行。 –

2

你可以試試這個 -

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

喜@ krishnraj,林蛙,你的解決方案看起來很優雅... –

+1

窗口功能是一個很好的路要走,但'ROW_NUMBER()'是錯誤的這項工作。這種特殊用法會爲每個具有相同'name'值的組中的最低''id'行產生錯誤的結果。 –

+0

@JohnBollinger:你是對的......我修改了我的答案。感謝您指出。 –