分页和INNER JOIN

Posted

技术标签:

【中文标题】分页和INNER JOIN【英文标题】:Pagination and INNER JOIN 【发布时间】:2012-04-28 15:23:30 【问题描述】:

我有一种情况需要与INNET JOIN 一起进行分页。这是我遇到的类似情况:

DECLARE @categories AS TABLE(
    CatID INT,
    CategoryName NVARCHAR(100)
);

DECLARE @fooTable AS TABLE(
    ID INT,
    CatID INT,
    Name NVARCHAR(100),
    MinAllow INT,
    Price DECIMAL(18,2)
);

INSERT INTO @categories  VALUES(1, 'Cat1');
INSERT INTO @categories  VALUES(2, 'Cat2');
INSERT INTO @categories  VALUES(3, 'Cat3');
INSERT INTO @categories  VALUES(4, 'Cat4');
INSERT INTO @categories  VALUES(5, 'Cat5');

INSERT INTO @fooTable  VALUES(1, 1, 'Product1', 2, 112.2);
INSERT INTO @fooTable  VALUES(3, 1, 'Product3', 5, 233.32);
INSERT INTO @fooTable  VALUES(6, 1, 'Product6', 4, 12.43);
INSERT INTO @fooTable  VALUES(7, 4, 'Product7', 4, 12.43);
INSERT INTO @fooTable  VALUES(8, 5, 'Product8', 4, 12.43);

这些是我的记录。如您所见,某些类别在@fooTable 中没有任何产品。作为下一步,我们有以下SELECT 声明:

SELECT * FROM @fooTable ft
INNER JOIN (
    SELECT ROW_NUMBER() OVER (ORDER BY CatID) AS RowNum, * FROM @categories
) AS cat ON (cat.CatID = ft.CatID);

这是一个基本的JOIN,除了输出还会携带类别的行号。这个查询我得到的结果如下:

ID   CatID   Name          MinAllow    Price     RowNum   CatID    CategoryName
---- ------- ------------- ----------- --------- -------- -------- -------------
1    1       Product1      2           112.20    1        1        Cat1
3    1       Product3      5           233.32    1        1        Cat1
6    1       Product6      4           12.43     1        1        Cat1
7    4       Product7      4           12.43     4        4        Cat4
8    5       Product8      4           12.43     5        5        Cat5

当您查看RowNum 列时,您会发现这些值不适合分页。因此,当我尝试按如下方式对该表进行分页时,我得到了一个不正确的输出:

SELECT * FROM @fooTable ft
INNER JOIN (
    SELECT ROW_NUMBER() OVER (ORDER BY CatID) AS RowNum, * FROM @categories
)AS cat ON (cat.CatID = ft.CatID) AND (cat.RowNum BETWEEN 1 AND 2);

我的实际情况与此类似,但该查询非常复杂,我需要使用 INNER JOIN 使其工作。我希望我说清楚了。知道我是如何得到这样的工作的吗?

编辑

根据我第一次选择查询的上述结果,我应该能够在我的第二次查询中检索到CatID 为 1 和 4 的产品。这就是我的目标。

【问题讨论】:

您应该在第一个SELECT 中使用ROW_NUMBER() OVER(ORDER BY ...) 而不是在派生表INNER JOIN (SELECT ...) as cat 中。 @BogdanSahlean 谢谢,但这并不能解决我的主要问题。我想对类别而不是产品进行分页。基于此,我应该检索正确的产品。我的意思是,在上述情况下,我应该能够获得 CatID 为 1 和 4 的产品。 看我的回答。你可以使用DENSE_RANK function。 【参考方案1】:

一个解决方案可以是下一个解决方案:

SELECT  x.*
FROM
(
        SELECT  ft.*, 
                cat.CategoryName,
                DENSE_RANK() OVER (ORDER BY ft.CatID) AS Rnk
        FROM @fooTable ft
        INNER JOIN @categories cat ON (cat.CatID = ft.CatID)
) AS x
WHERE   x.Rnk BETWEEN 1 AND 2

结果:

ID CatID Name     MinAllow Price   CategoryName Rnk
-- ----- -------- -------- ------- ------------ ---
1  1     Product1 2        112.20  Cat1         1
3  1     Product3 5        233.32  Cat1         1
6  1     Product6 4        12.43   Cat1         1
7  4     Product7 4        12.43   Cat4         2

【讨论】:

以上是关于分页和INNER JOIN的主要内容,如果未能解决你的问题,请参考以下文章

INNER JOIN LIMIT 1 使用分页

left join分页查询

ExtJs - 基于远程数据的分页和缓冲网格,没有远程分页和过滤

基于 mybatis 的分页和过滤查询

分页和中间件

逻辑分页和物理分页