2016-01-07 23 views
7

私は愚かな質問をしていた場合、私はとても残念SQLで最高ではないよ:)SQL - SELECT句の再帰的な条件

のは、このようなテーブルを持ってみましょう:

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

ユニーク。

そして、私はこのような結果を取得しようとしている:

|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ユニークある場合nameその後、display_name = 'nickname'
  2. ある場合次にdisplay_name = 'name'
  3. name
  4. display_name = 'name (nickname)'その後、 not_unique

であれば、私は唯一の1つのSQLクエリでそれを達成することはできますか?もしそうなら - どのように?そうでない場合 - 代替案は何ですか?

現在のところ、私はプログラミング言語を使用していますが、結果の各行ごとに別のSQLクエリを送信して、同じ名前の他のレコードがあるかどうかを確認する必要があります。全体のテーブル(4 000行と成長)。

答えて

7

あなたは指定された行のためnameは、サブクエリを実行せずに一意であるかどうかを判断するためにCOUNT()の窓関数のバージョンを使用することができます。たとえば:

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、私の頭に浮かぶ2つの質問:1) 'OVER(PARTITION BY)'コマンドは 'sqlserver'のためのものですか? 2)なぜ 'row_number'が機能しないのでしょうか?ありがとう –

+0

@AndyKの 'OVER()'節は、集計関数の代わりに 'COUNT()'をウィンドウ関数にするものです。これらはSQL2003以降の標準的なSQL機能であり、SQL2008で拡張されています。 SQL Server以外の多くのSQLデータベースでは、OracleとPostgreSQLが実装されていますが、多くは2つありますが、すべてではありません(MySQLはより顕著な例外の1つです)。 –

+0

@AndyKの 'ROW_NUMBER()'関数は、 'OVER()'句で定義されたパーティショニングやオーダーに対する現在の行の順序番号を返します。これにより、任意のパーティションの2番目以降の行が2つ以上の行を持つパーティションに属すると認識することができますが、行番号が '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:そうです...私は自分の答えを修正しました。指摘してくれてありがとう。 –