【问题标题】:SQL Pagination Query with order by带有 order by 的 SQL 分页查询
【发布时间】:2012-02-24 07:02:16
【问题描述】:

我正在尝试编写一个查询来提取多个字段并为它们分配别名。其中一个别名实际上是两个字段的总和。这实际上是我最大的问题,因为该别名是排序的可能“字段”之一,否则我可以取出所有别名而没有这个问题。无论如何,我需要能够传入一个以编程方式排序的字段。但是因为需要用SQL进行分页,所以不能使用LIMIT的优雅功能,只能使用子查询。

这是大问题出现的地方。因为我绝对必须在子查询中选择至少 2 列(因为我需要 ID 字段用于限制目的,并且总和别名作为按字段排序),我不能将其用作“And ID Not In(子查询)”,因为您只能以这种方式返回一个字段。因此,我将向您展示我的代码,然后解释我得到的结果。

SELECT     TOP (50) dbo.tblMailList.mail_ID AS Expr1, dbo.tblMailList.mail_NameTitle AS Expr2, dbo.tblMailList.mail_FirstName AS Expr3, 
                      dbo.tblMailList.mail_LastName AS Expr4, dbo.tblMailList.mail_Company AS Expr5, dbo.tblMailList.mail_Institution AS Expr6, 
                      SUM(dbo.tblItem.item_pr + dbo.tblItem.item_premium) AS Expr7, dbo.tblMailList.mail_Comp_Art, dbo.tblMailList.mail_Comp_IndArt, 
                      dbo.tblMailList.mail_Comp_GenAm, dbo.tblMailList.mail_Comp_Fire, dbo.tblMailList.mail_Comp_Jewelry, dbo.tblMailList.mail_Comp_Ceramic, 
                      dbo.tblMailList.mail_Interest
FROM         (SELECT     TOP (50) tblMailList_1.mail_ID AS Expr1, tblMailList_1.mail_NameTitle AS Expr2, tblMailList_1.mail_FirstName AS Expr3, 
                                              tblMailList_1.mail_LastName AS Expr4, tblMailList_1.mail_Company AS Expr5, tblMailList_1.mail_Institution AS Expr6, 
                                              SUM(tblItem_1.item_pr + tblItem_1.item_premium) AS Expr7, tblMailList_1.mail_Comp_Art, tblMailList_1.mail_Comp_IndArt, 
                                              tblMailList_1.mail_Comp_GenAm, tblMailList_1.mail_Comp_Fire, tblMailList_1.mail_Comp_Jewelry, tblMailList_1.mail_Comp_Ceramic, 
                                              tblMailList_1.mail_Interest
                       FROM          dbo.tblItem AS tblItem_1 INNER JOIN
                                              dbo.tblBidder AS tblBidder_1 ON tblItem_1.item_bidder_number = tblBidder_1.bidder_number AND 
                                              tblItem_1.item_sale_id = tblBidder_1.bidder_sale_id INNER JOIN
                                              dbo.tblMailList AS tblMailList_1 ON tblBidder_1.bidder_mail_id = tblMailList_1.mail_ID
                       WHERE      (tblMailList_1.mail_Comp_Art <> '1' OR
                                              tblMailList_1.mail_Comp_Art IS NULL) AND (tblMailList_1.mail_Comp_IndArt <> '1' OR
                                              tblMailList_1.mail_Comp_IndArt IS NULL) AND (tblMailList_1.mail_Comp_GenAm <> '1' OR
                                              tblMailList_1.mail_Comp_GenAm IS NULL) AND (tblMailList_1.mail_Comp_Fire <> '1' OR
                                              tblMailList_1.mail_Comp_Fire IS NULL)
                       GROUP BY tblMailList_1.mail_Company, tblMailList_1.mail_Institution, tblMailList_1.mail_LastName, tblMailList_1.mail_FirstName, 
                                              tblMailList_1.mail_NameTitle, tblMailList_1.mail_ID, tblMailList_1.mail_Comp_Art, tblMailList_1.mail_Comp_IndArt, 
                                              tblMailList_1.mail_Comp_GenAm, tblMailList_1.mail_Comp_Fire, tblMailList_1.mail_Interest, tblMailList_1.mail_Comp_Jewelry, 
                                              tblMailList_1.mail_Comp_Ceramic
                       ORDER BY Expr7 DESC) AS tblLimiter INNER JOIN
                      dbo.tblMailList ON NOT (tblLimiter.Expr1 = dbo.tblMailList.mail_ID) INNER JOIN
                      dbo.tblBidder ON dbo.tblBidder.bidder_mail_id = dbo.tblMailList.mail_ID INNER JOIN
                      dbo.tblItem ON dbo.tblItem.item_bidder_number = dbo.tblBidder.bidder_number AND dbo.tblItem.item_sale_id = dbo.tblBidder.bidder_sale_id
WHERE     (dbo.tblMailList.mail_Comp_Art <> '1' OR
                      dbo.tblMailList.mail_Comp_Art IS NULL) AND (dbo.tblMailList.mail_Comp_IndArt <> '1' OR
                      dbo.tblMailList.mail_Comp_IndArt IS NULL) AND (dbo.tblMailList.mail_Comp_GenAm <> '1' OR
                      dbo.tblMailList.mail_Comp_GenAm IS NULL) AND (dbo.tblMailList.mail_Comp_Fire <> '1' OR
                      dbo.tblMailList.mail_Comp_Fire IS NULL) AND (NOT (dbo.tblMailList.mail_ID = tblLimiter.Expr1))
GROUP BY dbo.tblMailList.mail_Company, dbo.tblMailList.mail_Institution, dbo.tblMailList.mail_LastName, dbo.tblMailList.mail_FirstName, 
                      dbo.tblMailList.mail_NameTitle, dbo.tblMailList.mail_ID, dbo.tblMailList.mail_Comp_Art, dbo.tblMailList.mail_Comp_IndArt, 
                      dbo.tblMailList.mail_Comp_GenAm, dbo.tblMailList.mail_Comp_Fire, dbo.tblMailList.mail_Interest, dbo.tblMailList.mail_Comp_Jewelry, 
                      dbo.tblMailList.mail_Comp_Ceramic
ORDER BY Expr7 DESC

这个问题是,如果子查询选择前 0,则什么都不返回,这很明显,但我需要尝试,因为我已经尝试了很多。选择 50 时,它将返回 50 行,其中 SUM 总计较大。 When 100 is selected, it returns the same 50 (because of the original top 50), but the SUM totals are twice as big...

现在我也有这个到“FROM”语句被反转的地方,与子查询本身的顺序相同,如下所示:

SELECT     TOP (50) tblMailList.mail_ID AS Expr1, tblMailList.mail_NameTitle AS Expr2, tblMailList.mail_FirstName AS Expr3, 
                      tblMailList.mail_LastName AS Expr4, tblMailList.mail_Company AS Expr5, tblMailList.mail_Institution AS Expr6, 
                      SUM(tblItem.item_pr + tblItem.item_premium) AS Expr7, tblMailList.mail_Comp_Art, tblMailList.mail_Comp_IndArt, tblMailList.mail_Comp_GenAm, 
                      tblMailList.mail_Comp_Fire, tblMailList.mail_Comp_Jewelry, tblMailList.mail_Comp_Ceramic, tblMailList.mail_Interest
FROM         dbo.tblItem AS tblItem INNER JOIN
                      dbo.tblBidder AS tblBidder ON tblItem.item_bidder_number = tblBidder.bidder_number AND tblItem.item_sale_id = tblBidder.bidder_sale_id INNER JOIN
                      dbo.tblMailList AS tblMailList ON tblBidder.bidder_mail_id = tblMailList.mail_ID LEFT OUTER JOIN
                          (SELECT     TOP (50) tblMailList_1.mail_ID AS Expr1, tblMailList_1.mail_NameTitle AS Expr2, tblMailList_1.mail_FirstName AS Expr3, 
                                                   tblMailList_1.mail_LastName AS Expr4, tblMailList_1.mail_Company AS Expr5, tblMailList_1.mail_Institution AS Expr6, 
                                                   SUM(tblItem_1.item_pr + tblItem_1.item_premium) AS Expr7, tblMailList_1.mail_Comp_Art, tblMailList_1.mail_Comp_IndArt, 
                                                   tblMailList_1.mail_Comp_GenAm, tblMailList_1.mail_Comp_Fire, tblMailList_1.mail_Comp_Jewelry, tblMailList_1.mail_Comp_Ceramic, 
                                                   tblMailList_1.mail_Interest
                            FROM          dbo.tblItem AS tblItem_1 INNER JOIN
                                                   dbo.tblBidder AS tblBidder_1 ON tblItem_1.item_bidder_number = tblBidder_1.bidder_number AND 
                                                   tblItem_1.item_sale_id = tblBidder_1.bidder_sale_id INNER JOIN
                                                   dbo.tblMailList AS tblMailList_1 ON tblBidder_1.bidder_mail_id = tblMailList_1.mail_ID
                            WHERE      (tblMailList_1.mail_Comp_Art <> '1' OR
                                                   tblMailList_1.mail_Comp_Art IS NULL) AND (tblMailList_1.mail_Comp_IndArt <> '1' OR
                                                   tblMailList_1.mail_Comp_IndArt IS NULL) AND (tblMailList_1.mail_Comp_GenAm <> '1' OR
                                                   tblMailList_1.mail_Comp_GenAm IS NULL) AND (tblMailList_1.mail_Comp_Fire <> '1' OR
                                                   tblMailList_1.mail_Comp_Fire IS NULL)
                            GROUP BY tblMailList_1.mail_Company, tblMailList_1.mail_Institution, tblMailList_1.mail_LastName, tblMailList_1.mail_FirstName, 
                                                   tblMailList_1.mail_NameTitle, tblMailList_1.mail_ID, tblMailList_1.mail_Comp_Art, tblMailList_1.mail_Comp_IndArt, 
                                                   tblMailList_1.mail_Comp_GenAm, tblMailList_1.mail_Comp_Fire, tblMailList_1.mail_Interest, tblMailList_1.mail_Comp_Jewelry, 
                                                   tblMailList_1.mail_Comp_Ceramic
                            ORDER BY Expr7 DESC) AS tblLimiter ON tblLimiter.Expr1 > 0
WHERE     (tblMailList.mail_Comp_Art <> '1' OR
                      tblMailList.mail_Comp_Art IS NULL) AND (tblMailList.mail_Comp_IndArt <> '1' OR
                      tblMailList.mail_Comp_IndArt IS NULL) AND (tblMailList.mail_Comp_GenAm <> '1' OR
                      tblMailList.mail_Comp_GenAm IS NULL) AND (tblMailList.mail_Comp_Fire <> '1' OR
                      tblMailList.mail_Comp_Fire IS NULL) AND (NOT (tblMailList.mail_ID = tblLimiter.Expr1))
GROUP BY tblMailList.mail_Company, tblMailList.mail_Institution, tblMailList.mail_LastName, tblMailList.mail_FirstName, tblMailList.mail_NameTitle, 
                      tblMailList.mail_ID, tblMailList.mail_Comp_Art, tblMailList.mail_Comp_IndArt, tblMailList.mail_Comp_GenAm, tblMailList.mail_Comp_Fire, 
                      tblMailList.mail_Interest, tblMailList.mail_Comp_Jewelry, tblMailList.mail_Comp_Ceramic
ORDER BY Expr7 DESC

但是,这与其他方式完全相同(返回结果的方式)。

我真的希望我能做一个“AND NOT IN (sub query)”,因为我可以毫无问题地完成这些工作。但是由于 Expr7 中的 SUM,我不能这样做。而且我是一个 MySQL 人,所以我对 SQL 知之甚少。我希望我提供了足够的信息。如果没有,请告诉我。感谢所有回复。

【问题讨论】:

  • 您可以通过从查询中删除不需要解释问题的所有内容来简化此操作...
  • @PeterLang 我真的应该有,但没想到。然而,康拉德已经回答了这个问题。不过还是谢谢。

标签: sql sql-server pagination subquery limit


【解决方案1】:

不要使用TOP 50 进行分页,而是使用ROW_NUMBER,然后使用where

WITH CTE AS (
SELECT     
           ROW_NUMBER() OVER (ORDER BY  SUM(dbo.tblItem.item_pr + dbo.tblItem.item_premium) ) RN,
           dbo.tblMailList.mail_ID AS Expr1, dbo.tblMailList.mail_NameTitle AS Expr2, dbo.tblMailList.mail_FirstName AS Expr3, 
           dbo.tblMailList.mail_LastName AS Expr4, dbo.tblMailList.mail_Company AS Expr5, dbo.tblMailList.mail_Institution AS Expr6, 
           SUM(dbo.tblItem.item_pr + dbo.tblItem.item_premium) AS Expr7, 
           dbo.tblMailList.mail_Comp_Art, dbo.tblMailList.mail_Comp_IndArt, 
           dbo.tblMailList.mail_Comp_GenAm, dbo.tblMailList.mail_Comp_Fire, dbo.tblMailList.mail_Comp_Jewelry, dbo.tblMailList.mail_Comp_Ceramic, 
 .....
)
SELECT * FROM CTE WHERE rn Between 50 and 100

【讨论】:

  • 欢迎您。顺便说一句,我在帖子中没有提到的是,您可以添加另一个 ROW_NUMBER(),但可以颠倒顺序的方向。这将使您能够轻松创建“最后一个”按钮或最后一个页码
  • 好吧,我实际上有另一个查询,它只是提取结果总数的计数,但最终使用另一个行号会更容易吗?听起来它会做同样的事情,但我不太确定我会如何设置它。
  • 它确实做同样的事情,但使用一个查询而不是两个。您可以随时通过(RN + ReverseRN) / PageSize 确定任何记录的页数。而且由于您已经在计算 RN,因此 ReverseRN 应该会越来越便宜。
  • 好的,那么ROW_NUMBER() OVER (ORDER BY SUM(SUM(dbo.tblItem.item_pr + dbo.tblItem.item_premium) ) RN, ROW_NUMBER() OVER (ORDER BY SUM(dbo.tblItem.item_pr + dbo.tblItem.item_premium) DESC) REVERSERN?
  • 是的,它可以为您节省额外的查询
猜你喜欢
  • 2013-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多