我正在尝试在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 |
答案 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.movie和genres.movie都匹配movies.movieID,这将有效 - 但通常我喜欢看到比这更好的外键。例如,如果Actor.movie确实包含“movieID”,则将其命名为“movieID” - 否则我认为我正在寻找
答案 2 :(得分:2)
你的问题确实有两个不同的问题。
1)如何编写SQL查询以获取页面所需的结果。
Mark和Leigh都有很好的解决方案。我个人更喜欢Leigh's。
我会在你去的时候添加转储你的结果(这里所有人都知道这一点,但是为子孙后代记录了一件好事)因为很容易假设你得到的结果与你想象的不同。
此外,它与下一步特别相关。
2)如何正确显示结果。
为此,您必须了解cfoutput的“group”属性是如何工作的。它只是检查您选择的列的值是否从上一行更改。这意味着您必须按组列排序,否则分组将显示错误。
例如:
类别,产品
如果您对上述结果进行了检查,则会出现错误,因为每次切换类别时,分组输出都会显示出来。另一方面,以下结果集可以正常工作:
这样做的结果是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">
的电影,然后进行查询查询以分别获取每部电影的演员和流派。