2009-06-10 10 views
0

私はこれらのテーブルを持っています:多対多のテーブル+カンマ区切りでSQL多重結合

メディアテーブル - id int主キー、uri varchar。
media_to_people - media_id intプライマリキー、people_id intプライマリキー
people-id intプライマリキー、名前varchar、role int-roleメディア、またはその両方に関連するアーティスト、パブリッシャ、ライター、アクターなどの人物を指定します。範囲(1-10)

これは私がメディアを選択における関連するすべての人々を取得したい多くの関係

に多いました。だからメディアに関連する10人の人がいるなら、10人はすべて来なければならない。

さらに、特定のメディアに同じロールを持つ複数のユーザーが存在する場合は、そのロールの列の下にコンマ区切りの値を指定する必要があります。

結果の見出しはmedia.id、media.uri、people.name(actor)、people.name(artist)、people.name(publisher)などのようにする必要があります。

私はsqliteを使用しています。

答えて

3

私はAlex Martelliのanswerに同意します。これは、データを複数行で取得し、アプリケーションで処理する必要があることに同意します。

ジョインだけでこれを実行しようとすると、各ロールタイプのpeopleテーブルに参加する必要があります。また、各ロールに複数の人がいる場合、これらのロールの間にデカルトがあります。

だからGROUP_CONCAT()でこれを行うと、各役割のためにあなたの選択リストのスカラー副問合せを生成する必要があります。

SELECT m.id, m.uri, 
(SELECT GROUP_CONCAT(name) 
    FROM media_to_people JOIN people ON (people_id = id) 
    WHERE media_id = m.id AND role = 1) AS Actors, 
(SELECT GROUP_CONCAT(name) 
    FROM media_to_people JOIN people ON (people_id = id) 
    WHERE media_id = m.id AND role = 2) AS Artists, 
(SELECT GROUP_CONCAT(name) 
    FROM media_to_people JOIN people ON (people_id = id) 
    WHERE media_id = m.id AND role = 3) AS Publishers 
FROM media m; 

これは本当に醜いです!自宅でこれを試してはいけません!

SQLのみを使用してピボットテーブルをフォーマットしようとしないでください。

+0

これは完全に動作します!これはまさに私が必要なものです!それはパフォーマンスを激しくしますか? – jetru

+1

はい!それはパフォーマンスを強く打つ!だから私はあなたにそれをしないように言ったのです!それに加えて、醜い、維持不能なコードです。 –

7

SQLiteは初心者にとって必要な "ピボット"機能を持っておらず、 "カンマ区切り値"部分は間違いなくプレゼンテーションの問題です。 SQLのどの方言が関係していても、それはあなたがクライアントでやる仕事の一部です報告機能またはプログラミング言語。

データにSQLを使用し、他のレイヤにプレゼンテーションを残します。

あなたはあなたのデータは

SELECT media.id, media.uri, people.name, people.role 
FROM media 
JOIN media_to_people ON (media.id = media_to_people.media_id) 
JOIN people ON (media_to_people.people_id = people.id) 
WHERE media.id = ? 
ORDER BY people.role, people.name 

(?あなたがあなたのクライアントに依存した方法で探している特定のメディアIDに拘束されることに、SQLiteの中でパラメータを示すための一つの方法です取得する方法

);データはDBからクライアントコードに複数の行で渡され、クライアントコードで簡単にそれらを1つの列形式にまとめることができます。

クライアントとして使用している環境や言語について何も知らなくても、クライアント側の部分をコーディングする方法は、私たちにとっては難しいことです。しかし、Pythonで、たとえば:

def showit(dataset): 
    by_role = collections.defaultdict(list) 
    for mediaid, mediauri, name, role in dataset: 
    by_role[role].append(name) 
    headers = ['mediaid', 'mediauri'] 
    result = [mediaid, mediauri] 
    for role in sorted(by_role): 
    headers.append('people(%s)' % role) 
    result.append(','.join(by_role[role])) 
    return ' '.join(headers) + '\n' + ' '.join(result) 

でもこれは非常にあなたの仕様と一致しません - あなたはまた、その役割のエンコードされたintとして、および言及を指定しているときには、このような「人(アーティスト)」などのヘッダを求めますintから文字列 'artist'に移動する方法はないので、スペックを正確に一致させることは明らかに不可能です...しかし、それは私の独創性が得られるほど近いです;-)。

+0

+1クライアントアプリケーション言語の行の後処理を推奨します。 –

+0

ですから、異なる役割のpeople.name列をフェッチする方法はありませんか? 私は次のようなものを考えていました: SELECT media.id、media.uri、artists.name、publishers.name FROM media JOIN media_to_people ON media_to_people.media_id = media.id JOIN people ASアーティスト、人物AS publishers ON(artist。 id = media_to_people.people_id AND artists.role = 2)OR(publishers.role = 8 AND publishers.id = media_to_people.people_id) これは意図したとおりには機能しません... – jetru

+0

ヘッダー名はあまり重要ではありません一列に並べる私はすべてのものが1つのクエリで完了します。 私はCを書いています。なぜ結果の後処理を避けたいのか想像できます。 ;) – jetru

関連する問題