2012-04-12 8 views
0

私はCF/SQLで非常に簡単なことをしようとしていますが、私が間違っていることを理解できないようです。 ColdFusionでSQL結合に問題がある

私はこれらのテーブルを持っている:

movies  genres  actors  moviesGenres  moviesActors 
------  ------  ------  ------------  ------------ 
movieId  genreId actorId  id    id 
title  name  fname  movie   movie 
         lname  genre   actor 

私は各映画のジャンルと、単純にすべてのムービーを一覧表示し、クエリ、(複数選択可能)と各映画の俳優を書くしようとしている(再び、複数選択可能) 。

ジャンルを含むようにクエリを書き込むと、すべて正常に動作します。私は、クエリ自体のために、movieIdでグルーピングしてから、ジャンルごとに別々に使用します。

しかし、私が俳優を含めようとすると、すべてが爆発し、グループ化が失敗したように見えます。任意の助けを事前に

SELECT m.movieId, m.title, m.releaseDate, m.description, g.name, a.fname, a.lname 
FROM movies m 
    INNER JOIN genres g ON g.genreId IN (SELECT genre FROM moviesGenres WHERE movie = m.movieId) 
    INNER JOIN actors a ON a.actorID IN (SELECT actor FROM moviesActors WHERE movie = m.movieId) 
ORDER BY m.title 

感謝を:ここで

は両方のためのSQLクエリが参加します!

UPDATE:

リーとマークによって提供されるクエリは、全体的に動作しているようですが、私はまだ俳優がで複数回表示見ています。ここに私のコードは次のとおりです。

<tbody> 
    <cfoutput query="variables.movieList" group="movieId"> 
     <tr> 
     <td><a href="##">#title#</a></td> 
     <td><cfoutput group="name">#name# | </cfoutput></td> 
     <td><cfoutput group="actorId">#actorId# | </cfoutput></td> 
     </tr> 
    </cfoutput> 
</tbody> 

私も、最終的なタグをグループ化することなく、それを試してみたが、それは動作しませんでした。テストの簡潔さのために、a.lNameとa.fNameをa.actorIdに変更したことに注意してください。

サンプル行は次のようになります。

The Godfather Action | Drama | 1 | 2 | 1 | 2 | 
+0

は、タグ編集をロールバック。 – Leigh

+0

SELECT DISTINCT m.movi​​eID、m.title ...などのようにクエリに "Distinct"を追加してみてください。 –

答えて

3

あなたが参加内のすべてのテーブルを関連付ける必要があります。それ以外の場合はcartesian productになります。サブクエリではなくジャンクションテーブルにも参加してください。正しいORDER BYを使用すると、<cfoutput group="..">を使用して、必要に応じて出力をフォーマットすることができます。

テストされていませんが、これらの行に沿ったものです。

コメントに基づいて
SELECT m.movieId, m.title, m.releaseDate, m.description, g.name, a.actorID, a.fname, a.lname 
FROM movies m 
     LEFT JOIN moviesGenres mg ON mg.movie = m.movieID 
     LEFT JOIN genres g ON g.genreID = mg.genre 
     LEFT JOIN moviesActors ma ON ma.movie = m.movieID 
     LEFT JOIN actors a ON a.actorId = ma.actor 
// since movie names may not be unique, do a secondary sort on movieID 
ORDER BY m.title, m.movieID, g.Name, a.fName, a.lName 

編集:

スティーブが述べたように、cfoutput groupを使用した場合の結果がソートされ、正しく動作する機能のために同じようにグループ化する必要があります。より詳細な説明についてはSee his answerを参照してください。

アプローチの代わりに、構造を使用して固有のジャンルとアクターを生成する方法もあります。上記のSQLクエリは、更新されたサンプルに合わせて若干変更されています。

<table border="1"> 
<!--- group by ID in case multiple movies have the same name ---> 
<cfoutput query="yourQuery" group="movieID"> 

    <!--- use structures to save unique genres and actors ---> 
    <cfset genres = {}> 
    <cfset actors = {}> 
    <cfoutput> 
     <cfset genres[name] = true> 
     <cfset actors[actorID] = true> 
    </cfoutput> 

    <!--- display results ---> 
    <tr><td>#Title#</td> 
     <td>#structKeyList(genres, "|")#</td> 
     <td>#structKeyList(actors, "|") #</td> 
    </tr> 
</cfoutput> 
</table> 
+0

それはすばらしいです...素晴らしい心は似ています。あなたの構文を愛して;) –

+0

笑..あなたのものは美しさのものです) – Leigh

+0

オプションを比較するときに考えることの1つは、鉱山とリーの長さが似ている一方、リーのものはより詳細で読みやすく簡潔ですが、ジャンル "と"俳優 "。 (だから私はあなたがリーを選択することをお勧めします) –

2

あなたの構文がわかりません。私はあなたのsubselectsとエイリアシングがあなたの結果にうんざりしていると推測しています。あなたがしていることを私が捕まえたら、これらのブリッジテーブルに参加することです。 - しかし、通常、私はそれよりも良いという名前の外部キーを見たい

SELECT m.movieId, m.title, m.releaseDate, m.description, g.name, a.fname, a.lname 
FROM movies m 
    INNER JOIN movieGenres mg ON m.movieID = mg.movie 
    INNER JOIN genres g ON g.genreID = mg.genre 
    INNER JOIN movieactors ma on ma.movie = m.movieID 
    INNER JOIN actors a on ma.actor = a.actorID 
ORDER BY m.title 

actors.movi​​eとgenres.movi​​e両方マッチmovies.movi​​eID場合、これは動作します:私はこのような何かをするだろう。たとえば、Actor.movi​​eに実際に「movieID」が含まれている場合は「movieID」と名前を付けてください。そうでない場合は私が探していると思います。

+0

FYI - リー答えは、より柔軟性のある、または完全な結果セットを与えるかもしれません。内部結合は、すべての4つのテーブルに少なくとも1つのレコードを持つムービーを返しますが、左の結合では、ジャンルまたはアクターにマップされていないムービーが許可されます。 –

+1

+1の命名規則についてのコメント。一貫した命名規則を維持することは、より直感的なものになります。これは、大きなスキーマでは特に重要です。 – Leigh

+0

このクエリは多大な助けに見えましたが、私はまだアクター上で複数の出力を見ています。私は上記の元の投稿を更新しました。あなたとMarkの両方に感謝します! – Gary

0

同じ質問ではアクターとジャンルの両方で使用できません。あなたの最善の策は、<cfoutput query="someQry" group="movieId">で映画だけを出力してから、各映画の俳優とジャンルを別々に取得するためのクエリのクエリです。

+0

いいえ、 'cfoutput'には正しいjoinと複数の' group'節がある可能性があります。 – Leigh

+0

可能性がありますが、コードのエラーが発生しやすくなり、保守が難しくなります。クエリのクエリは非常に高速であり、コードをより読みやすく柔軟にします。 –

+0

いいえ、 'group'は他の機能と同じです。機能がどのように動作するか誤解しない限り、エラーが発生しやすいわけではありません。 'group'機能は、入れ子にされたループを持つQoQのより単純な代替手段を提供することがよくあります。私の経験では、QoQは必ずしも高速ではありません。すべての反復で完全なクエリーオブジェクトを構築するのがオーバーヘッドだと思います。だから私は可能な限り避ける傾向があります。 – Leigh

2

あなたの質問には2つの問題があります。

1)あなたのページに必要な結果を得るためにSQLクエリを書く方法。

MarkとLeighの両方にこの問題の解決策があります。個人的に私はリーの方が好きです。

私はあなたが行ったときに結果をダンプして追加していきます(あなたはそれを知っているかもしれませんが、後世のために文書化しておくのは良いことです)。

また、特に次のステップに関係します。

2)結果を正しく表示する方法。

このため、cfoutputの "group"属性がどのように機能するかを理解する必要があります。これは、選択した列の値が前の行から変更されたかどうかを確認するだけです。これは、グループ列で注文する必要があることを意味します。そうしないと、グループ化が正しく表示されません。例えば

カテゴリ、製品

  • 食品、アップル
  • クリーナー、彗星
  • 食品、バナナ

あなたはそれ以上の結果を行った場合だろうカテゴリが切り替わるたびにグループ化された出力が表示されるため、間違って表示されます。以下の結果セットが、一方で、正常に動作します:

  • クリーナー、彗星
  • 食品、アップル
  • 食品を、バナナ

これの結論は、CFOUTPUTグループが依存していることです注文するので、1つのレベルで1つの列でのみ使用することができます(しかし、もちろん、あなたは好きなほど多くのレベルに行くことができます)。

解決策は、2番目の列グループをより手作業で処理することです。これは、例えばリストをどこかに構築し、それをループすることによって実現できます。

だから、あなたの例では、クエリのために、これは動作します:完全なタスクはCF特定のコードを含むことができるので、

<tbody> 
    <cfoutput query="variables.movieList" group="movieId"> 
     <cfset actors = ""> 
     <cfoutput> 
      <cfif NOT ListFindNoCase(actors,actorId)> 
       <cfset actors = ListAppend(actors,actorId)> 
      </cfif> 
     </cfoutput> 
     <tr> 
     <td><a href="##">#title#</a></td> 
     <td><cfoutput group="name">#name# | </cfoutput></td> 
     <td><cfloop list="actors" index="actor">#actor# | </cfloop></td> 
     </tr> 
    </cfoutput> 
</tbody> 
+0

+1。 'cfoutput group'の制限に注意することは重要です。 「グループ化」を並行して行うには、もう少し創造性が必要です。 – Leigh

+0

@スティーブ - 情報とコードをありがとう。私はグループ分けの仕組みがはるかに分かりました。私は皆の助けに感謝します。 – Gary

関連する問題