SQL逻辑:两个表(分组?)

时间:2009-11-25 00:01:51

标签: sql

我有两个表,一个电影表(mt,主表),以及一个列出这些电影可用的表(st,辅助表)。对于每个mt记录,有多个st记录。我需要一个将加入记录的查询,并允许我在两个表上运行查询。我目前使用这样的内连接:

SELECT * FROM
(
    SELECT ROW_NUMBER() OVER(ORDER BY " + orderField + @") AS RowNum,
           mt.ID AS mt_ID,
           mt.title AS mt_title,
           [...]
           st.ID AS st_ID,
           st.title AS st_title,
           [...]
    FROM mt AS mt 
    st AS st
    INNER JOIN sttable AS st on mt.ID =st.ID
    WHERE st.title=@variable <> 0 AND mt.title = @variable
)    
    as DerivedTableName
    WHERE RowNum between 
    ((@pageIndex - 1) * @pageSize + 1) and @pageIndex*@pageSize

这个问题是我需要能够使用RowNum和pageIndex遍历mt,并且查询为每部电影返回多条记录(例如,如果特定电影有8条记录,8,不是1,记录被退回)。我尝试过使用GROUP BY,但问题是它不允许我对下级表(st)中的字段执行查询。

非常感谢任何有关适当逻辑的帮助。

2 个答案:

答案 0 :(得分:1)

这是一个在派生表子查询中执行GROUP BY的解决方案,因此每个影片标题只能获得一行,并从中计算ROW_NUMBER()

然后在外部查询中再次将派生表的结果加入st。每个电影标题仍会有多行,但RowNum会重复,因此您可以正确过滤@pageIndex

SELECT * FROM
(
    SELECT ROW_NUMBER() OVER(ORDER BY " + orderField + @") AS RowNum,
           mt.ID AS mt_ID,
           mt.title AS mt_title,
           [...]
    FROM mt AS mt 
    INNER JOIN sttable AS st ON mt.ID =st.ID
    WHERE mt.title = @variable
    GROUP BY mt.ID
) mt1
INNER JOIN sttable AS st1 ON (mt1.ID = st1.ID)
WHERE mt1.RowNum BETWEEN 
    ((@pageIndex - 1) * @pageSize + 1) AND @pageIndex*@pageSize;

您必须在显示代码中循环外部查询的结果,并在值RowNum发生更改时开始新的输出行。这是一个非常明显的技术。

如果您想要执行类似MySQL的GROUP_CONCAT()功能,那么在Microsoft SQL Server中这很棘手(我假设您使用的是Microsoft)。

请参阅http://blog.shlomoid.com/2008/11/emulating-mysqls-groupconcat-function.html等描述使用FOR xml PATH ('')技巧的博客。

PS:鉴于你的口头描述,你的示例SQL查询没有意义,所以我尽力写出一些明智的东西。不保证它与您的架构匹配。


重新评论:我认为您不需要在子查询中的任何st列进行排序。我打算在子查询的选择列表中包含来自st的列。在子查询中加入st实例的唯一原因是将mt的行限制为st中具有匹配行的行。但是GROUP BY mt.ID确保每行mt只有一行(实际上因为这是SQL Server而不是MySQL,所以你需要命名选择列表的所有mt列在GROUP BY子句中。


重新发表您的第二条评论:

  

我想首先显示具有最近添加的相应st记录的mt行

如果使用分组功能,则可以向分组查询添加其他列。例如,每组date_added的最新mtMAX(st.date_added),您可以将此列添加到子查询中。

但是,请勿在子查询中使用ORDER BY。很少有任何理由对子查询进行排序,因为无论如何都可以通过在JOIN中使用子查询结果或使用子查询的其他操作来更改顺序。

您应该在外部查询中进行排序:

SELECT * FROM
(
    SELECT ROW_NUMBER() OVER(ORDER BY " + orderField + @") AS RowNum,
           mt.ID AS mt_ID,
           mt.title AS mt_title,
           [...] -- other mt.* columns
           MAX(st.date_added) AS latest_date_added
    FROM mt AS mt 
    INNER JOIN sttable AS st ON mt.ID =st.ID
    WHERE mt.title = @variable
    GROUP BY mt.ID, -- other mt.* columns
) mt1
INNER JOIN sttable AS st1 ON (mt1.ID = st1.ID)
WHERE mt1.RowNum BETWEEN 
    ((@pageIndex - 1) * @pageSize + 1) AND @pageIndex*@pageSize
ORDER BY mt1.latest_date_added DESC, st1.date_added DESC;

答案 1 :(得分:0)

我认为你不需要这两个:

FROM mt AS mt 
  st AS st

和此:

INNER JOIN sttable AS st on mt.ID = st.ID