我试图在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 |
您必须关联连接中的所有表。否则,你最终会得到一个笛卡尔乘积。因此,也加入联结表,而不是在子查询中使用它们。使用正确的 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
时,必须以相同的方式对结果进行排序和分组,以使功能正常工作。有关更详细的解释,请参阅他的回答。
另一种方法是使用结构来生成独特的类型和演员。请注意,上面的 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>
不确定我是否喜欢你的语法。我猜你的子选择和混叠正在搞砸你的结果。你追求的是加入这些桥表,如果我抓住你在做什么。我会做这样的事情:
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
如果 actor.movie 和 genres.movie 都匹配 movies.movieID - 这将起作用 - 但通常我喜欢看到外键命名得比这更好。例如,如果Actor.movie真的包含"movieID",则将其命名为"movieID" - 否则我认为我正在寻找
你的问题实际上有两个独立的问题。
1) 如何编写 SQL 查询来获取页面所需的结果。
马克和利都对这个问题有很好的解决方案。就我个人而言,我更喜欢费雯丽的。
我只会在你去的时候添加转储你的结果(这里的所有人都可能知道这一点,但为后代记录下来是一件好事),因为很容易假设你得到的结果与你想象的不一样。
此外,它与下一步特别相关。
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>
不能在同一查询中同时使用演员和流派。最好的办法是只输出带有<cfoutput query="someQry" group="movieId">
的电影,然后执行查询查询以分别获取每部电影的演员和流派。