在ColdFusion中遇到SQL Join问题

时间:2012-04-12 14:48:20

标签: sql coldfusion cfquery cfoutput

我正在尝试在CF / SQL中做一些非常简单的事情,但似乎无法弄清楚我做错了什么。

我有这些表格:

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

我正在尝试编写一个简单列出所有电影的查询,每个电影的类型(可能有多个选项)和每个电影的演员(再次,可能有多个选项)。

当我编写查询以仅包含类型时,一切正常。我用于查询本身,按movieId分组,然后单独围绕类型。

但是当我试图将演员包括在内时,一切都会爆炸,看起来分组似乎崩溃了。

这是两个连接的SQL查询:

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

提前感谢您的帮助!

更新:

Leigh和Mark提供的查询似乎总体上有效,但我仍然看到演员多次显示。这是我的代码:

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

4 个答案:

答案 0 :(得分: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

根据评论进行修改:

正如Steve所说,使用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>

答案 1 :(得分:2)

不确定我喜欢你的语法。我猜你的子选择和别名正在搞砸你的结果。如果我抓住你正在做的事情,你所追求的是加入这些桥牌桌。我会做这样的事情:

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” - 否则我认为我正在寻找

答案 2 :(得分:2)

你的问题确实有两个不同的问题。

1)如何编写SQL查询以获取页面所需的结果。

Mark和Leigh都有很好的解决方案。我个人更喜欢Leigh's。

我会在你去的时候添加转储你的结果(这里所有人都知道这一点,但是为子孙后代记录了一件好事)因为很容易假设你得到的结果与你想象的不同。

此外,它与下一步特别相关。

2)如何正确显示结果。

为此,您必须了解cfoutput的“group”属性是如何工作的。它只是检查您选择的列的值是否从上一行更改。这意味着您必须按组列排序,否则分组将显示错误。

例如:

类别,产品

  • Food,Apple
  • 清洁工,Comet
  • 食物,香蕉

如果您对上述结果进行了检查,则会出现错误,因为每次切换类别时,分组输出都会显示出来。另一方面,以下结果集可以正常工作:

  • 清洁工,Comet
  • Food,Apple
  • 食物,香蕉

这样做的结果是cfoutput组依赖于排序,所以你只能在任何一个级别的一列上使用它(当然,你可以按照你想要的那样深入多个级别)。

然后,解决方案是更多地手动处理第二列分组。例如,这可以通过在某处构建列表然后循环遍历它来实现。

因此,对于您的示例中的查询,这将起作用:

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

答案 3 :(得分:0)

您无法在同一查询中同时使用actor和流派。您最好的选择是输出<cfoutput query="someQry" group="movieId">的电影,然后进行查询查询以分别获取每部电影的演员和流派。