db2分页sql

我敢肯定,到目前为止,您已经以多种方式弄错了。 而且您可能很快将无法正确处理。 那么,当您可以实施业务逻辑时,为什么还要在SQL调整上浪费您的宝贵时间呢?

让我解释…

直到最近的SQL:2008标准 ,MySQL用户才知道的LIMIT .. OFFSET被标准化为以下简单语句:

SELECT *
FROM BOOK
OFFSET 2 ROWS
FETCH NEXT 1 ROWS ONLY

是。 关键字太多了。

SQL确实是一种非常冗长的语言。 就个人而言,我们真的很喜欢MySQL / PostgreSQLLIMIT .. OFFSET子句的简洁性,这就是为什么我们为jOOQ DSL API选择它的原因 。

在SQL中:

SELECT * FROM BOOK LIMIT 1 OFFSET 2

在jOOQ中:

select().from(BOOK).limit(1).offset(2);

现在,当您是SQL框架供应商时,或者在滚动自己的内部SQL抽象时,您可能会考虑标准化此简洁的小子句。 这是数据库中固有支持偏移分页的两种口味:

-- MySQL, H2, HSQLDB, Postgres, and SQLite
SELECT * FROM BOOK LIMIT 1 OFFSET 2-- CUBRID supports a MySQL variant of the
-- LIMIT .. OFFSET clause
SELECT * FROM BOOK LIMIT 2, 1-- Derby, SQL Server 2012, Oracle 12, SQL:2008
SELECT * FROM BOOK
OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY-- Ingres. Eek, almost the standard. Almost!
SELECT * FROM BOOK
OFFSET 2 FETCH FIRST 1 ROWS ONLY-- Firebird
SELECT * FROM BOOK ROWS 2 TO 3-- Sybase SQL Anywhere
SELECT TOP 1 ROWS START AT 3 * FROM BOOK-- DB2 (without OFFSET)
SELECT * FROM BOOK FETCH FIRST 1 ROWS ONLY-- Sybase ASE, SQL Server 2008 (without OFFSET)
SELECT TOP 1 * FROM BOOK

到目前为止,一切都很好。 这些都可以处理。 一些数据库将偏移量放在限制之前,另一些数据库则将限制放在偏移量之前,并且T-SQL系列将整个TOP子句放在SELECT列表之前。 这很容易模仿。 现在呢:

  • Oracle 11g及以下
  • SQL Server 2008及更低版本
  • 具有偏移量的DB2

( 请注意,您可以在DB2中启用各种替代语法 )

当您使用google搜索时,您会发现数百万种方法可以在那些较旧的数据库中模拟OFFSET .. FETCH 。 最佳解决方案始终涉及:

  • 在Oracle中使用带有ROWNUM筛选的双嵌套派生表
  • 在SQL Server和DB2中使用带有ROW_NUMBER()筛选的单嵌套派生表格

因此,您正在模仿它。

您认为您会做对吗?

让我们来解决一些您可能没有想到的问题。

首先,Oracle。 Oracle显然想创建一个最大的供应商锁定,只有苹果最近推出了Swift才超过了。 这就是为什么ROWNUM解决方案的性能最佳,甚至优于基于SQL:2003标准窗口函数的解决方案的原因。 不相信吗? 阅读有关Oracle偏移分页性能的这篇非常有趣的文章 。

因此,Oracle中的最佳解决方案是:

-- PostgreSQL syntax:
SELECT ID, TITLE
FROM BOOK
LIMIT 1 OFFSET 2-- Oracle equivalent:
SELECT *
FROM (SELECT b.*, ROWNUM rnFROM (SELECT ID, TITLEFROM BOOK) bWHERE ROWNUM <= 3 -- (1 + 2)
)
WHERE rn > 2

那真的等效吗?

当然不是。 您正在选择其他列,即rn列。 在大多数情况下,您可能并不在意,但是如果您想进行有限的子查询以与IN谓词一起使用怎么办?

-- PostgreSQL syntax:
SELECT *
FROM BOOK
WHERE AUTHOR_ID IN (SELECT IDFROM AUTHORLIMIT 1 OFFSET 2
)-- Oracle equivalent:
SELECT *
FROM BOOK
WHERE AUTHOR_ID IN (SELECT * -- Ouch. These are two columns!FROM (SELECT b.*, ROWNUM rnFROM (SELECT IDFROM AUTHOR) bWHERE ROWNUM <= 3)WHERE rn > 2
)

因此,如您所见,您将不得不执行一些更复杂SQL转换。 如果您要手动模拟LIMIT .. OFFSET ,则可以将ID列修补到子查询中:

SELECT *
FROM BOOK
WHERE AUTHOR_ID IN (SELECT ID -- betterFROM (SELECT b.ID, ROWNUM rn -- betterFROM (SELECT IDFROM AUTHOR) bWHERE ROWNUM <= 3)WHERE rn > 2
)

所以,更像是吧? 但是,由于您不是每次都手动编写此代码,因此您将开始创建自己的漂亮的内部SQL框架,该框架涵盖到目前为止所遇到的2-3个用例,对吗?

你能行的。 因此,您将自动regex-search-replace列名以产生上述内容。

所以现在,对吗?

当然不是! 因为您可以在顶级SELECT包含不明确的列名,但不能在嵌套选择中包含。 如果要这样做:

-- PostgreSQL syntax:
-- Perfectly valid repetition of two ID columns
SELECT BOOK.ID, AUTHOR.ID
FROM BOOK
JOIN AUTHOR
ON BOOK.AUTHOR_ID = AUTHOR.ID
LIMIT 1 OFFSET 2-- Oracle equivalent:
SELECT *
FROM (SELECT b.*, ROWNUM rnFROM (-- Ouch! ORA-00918: column ambiguously definedSELECT BOOK.ID, AUTHOR.IDFROM BOOKJOIN AUTHORON BOOK.AUTHOR_ID = AUTHOR.ID) bWHERE ROWNUM <= 3
)
WHERE rn > 2

不。 而且,由于您有多个ID实例,因此手动修补前面示例中的ID列的技巧不起作用。 并且将列重命名为随机值是很麻烦的,因为您自己的内部数据库框架的用户希望接收定义良好的列名称。 即ID和… ID

因此,解决方案是将列重命名两次。 在每个派生表中一次:

-- Oracle equivalent:
-- Rename synthetic column names back to original
SELECT c1 ID, c2 ID
FROM (SELECT b.c1, b.c2, ROWNUM rnFROM (-- synthetic column names hereSELECT BOOK.ID c1, AUTHOR.ID c2FROM BOOKJOIN AUTHORON BOOK.AUTHOR_ID = AUTHOR.ID) bWHERE ROWNUM <= 3
)
WHERE rn > 2

但是现在,我们完成了吗?

当然不是! 如果您将这样的查询加倍嵌套怎么办? 您是否考虑将ID列重命名为合成名称,然后再重新命名? ……让我们留在这里,谈论完全不同的事情:

SQL Server 2008是否可以使用相同的功能?

当然不是! 在SQL Server 2008中,最流行的方法是使用窗口函数。 即ROW_NUMBER() 。 因此,让我们考虑:

-- PostgreSQL syntax:
SELECT ID, TITLE
FROM BOOK
LIMIT 1 OFFSET 2-- SQL Server equivalent:
SELECT b.*
FROM (SELECT ID, TITLE, ROW_NUMBER() OVER (ORDER BY ID) rnFROM BOOK
) b
WHERE rn > 2 AND rn <= 3

就这样吧?

当然不是!

好的,我们已经遇到了这个问题。 我们不应该选择* ,因为在我们将其用作IN谓词的子查询的情况下,这会生成过多的列。 因此,让我们考虑使用综合列名称的正确解决方案:

-- SQL Server equivalent:
SELECT b.c1 ID, b.c2 TITLE
FROM (SELECT ID c1, TITLE c2,ROW_NUMBER() OVER (ORDER BY ID) rnFROM BOOK
) b
WHERE rn > 2 AND rn <= 3

但是现在我们明白了,对不对?

做出有根据的猜测: 不!

如果您在原始查询中添加ORDER BY子句,会发生什么情况?

-- PostgreSQL syntax:
SELECT ID, TITLE
FROM BOOK
ORDER BY SOME_COLUMN
LIMIT 1 OFFSET 2-- Naive SQL Server equivalent:
SELECT b.c1 ID, b.c2 TITLE
FROM (SELECT ID c1, TITLE c2,ROW_NUMBER() OVER (ORDER BY ID) rnFROM BOOKORDER BY SOME_COLUMN
) b
WHERE rn > 2 AND rn <= 3

现在,这在SQL Server中不起作用。 子查询不允许具有ORDER BY子句,除非它们也具有TOP子句(或SQL Server 2012中的OFFSET .. FETCH子句)。

好的,我们可以使用TOP 100 PERCENT进行调整,以使SQL Server满意。

-- Better SQL Server equivalent:
SELECT b.c1 ID, b.c2 TITLE
FROM (SELECT TOP 100 PERCENTID c1, TITLE c2,ROW_NUMBER() OVER (ORDER BY ID) rnFROM BOOKORDER BY SOME_COLUMN
) b
WHERE rn > 2 AND rn <= 3

现在,根据SQL Server,这是正确SQL,尽管您不能保证在查询执行后派生表的顺序将继续存在。 很可能是由于某种影响再次改变了顺序。

如果要在外部查询中按SOME_COLUMN进行排序, SOME_COLUMN必须再次转换SQL语句以添加另一个综合列:

-- Better SQL Server equivalent:
SELECT b.c1 ID, b.c2 TITLE
FROM (SELECT TOP 100 PERCENTID c1, TITLE c2,SOME_COLUMN c99,ROW_NUMBER() OVER (ORDER BY ID) rnFROM BOOK
) b
WHERE rn > 2 AND rn <= 3
ORDER BY b.c99

确实开始变得有点讨厌。 让我们猜一下是否:

这是正确的解决方案!

当然不是! 如果原始查询中包含DISTINCT怎么办?

-- PostgreSQL syntax:
SELECT DISTINCT AUTHOR_ID
FROM BOOK
LIMIT 1 OFFSET 2-- Naive SQL Server equivalent:
SELECT b.c1 AUTHOR_ID
FROM (SELECT DISTINCT AUTHOR_ID c1,ROW_NUMBER() OVER (ORDER BY AUTHOR_ID) rnFROM BOOK
) b
WHERE rn > 2 AND rn <= 3

现在,如果一位作家写了几本书怎么办? 是的, DISTINCT关键字应该删除这些重复项,并且有效地,PostgreSQL查询将首先正确删除重复项,然后应用LIMITOFFSET

但是, ROW_NUMBER()谓词 DISTINCT可以再次删除它们之前总是生成不同的行号。 换句话说, DISTINCT无效。

幸运的是,我们可以使用以下巧妙的小技巧再次调整此SQL :

-- Better SQL Server equivalent:
SELECT b.c1 AUTHOR_ID
FROM (SELECT DISTINCT AUTHOR_ID c1,DENSE_RANK() OVER (ORDER BY AUTHOR_ID) rnFROM BOOK
) b
WHERE rn > 2 AND rn <= 3

在此处阅读有关此技巧的更多信息:

SQL技巧:row_number()是SELECT,而density_rank()是SELECT DISTINCT 。

请注意, ORDER BY子句必须包含SELECT字段列表中的所有列。 显然,这会将SELECT DISTINCT字段列表中可接受的列限制为窗口函数的ORDER BY子句中允许的列(例如,没有其他窗口函数)。

我们当然也可以尝试使用通用表表达式来解决此问题,或者我们考虑

另一个问题?

当然是!

您甚至不知道窗口函数的ORDER BY子句中的列应该是什么? 您是否刚刚随机选择了任何一栏? 如果该列上没有索引该怎么办,您的窗口函数仍会执行吗?

当原始的SELECT语句还具有ORDER BY子句时,答案很容易,那么您应该采用该子句(如果适用,还要加上SELECT DISTINCT子句中的所有列)。

但是,如果您没有任何ORDER BY子句怎么办?

还有另一把戏! 使用“常量”变量:

-- Better SQL Server equivalent:
SELECT b.c1 AUTHOR_ID
FROM (SELECT AUTHOR_ID c1,ROW_NUMBER() OVER (ORDER BY @@version) rnFROM BOOK
) b
WHERE rn > 2 AND rn <= 3

是的,您需要使用一个变量,因为在SQL Server的那些ORDER BY子句中不允许使用常量。 痛苦的,我知道。

在此处阅读有关此@@ version技巧的更多信息 。

我们完成了吗?

可能不是! 但是,我们可能已经涵盖了大约99%的常见案例和边缘案例。 现在,我们可以睡个好觉了。

注意,所有这些SQL转换都是在jOOQ中实现的。 jOOQ是唯一认真对待SQL(带有所有缺点和警告)SQL抽象框架,它对所有这些疯狂行为进行了标准化。

如开头所述,使用jOOQ,您只需编写:

// Don't worry about general emulation
select().from(BOOK).limit(1).offset(2);// Don't worry about duplicate column names
// in subselects
select(BOOK.ID, AUTHOR.ID)
.from(BOOK)
.join(AUTHOR)
.on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
.limit(1).offset(2);// Don't worry about invalid IN predicates
select()
.from(BOOK)
.where(BOOK.AUTHOR_ID).in(select(AUTHOR.ID).from(AUTHOR).limit(1).offset(2)
);// Don't worry about the ROW_NUMBER() vs.
// DENSE_RANK() distinction
selectDistinct(AUTHOR_ID).from(BOOK).limit(1).offset(2);

使用jOOQ,您可以像编写PostgreSQL一样出色地编写Oracle SQL或Transact SQL! …不必完全跳起SQL船 ,而是继续使用JPA。

键集分页

现在,当然,如果您正在阅读我们的博客或我们的合作伙伴博客SQL Performance Explained ,那么现在您应该知道, OFFSET分页通常首先是一个不好的选择。 您应该知道,键集分页几乎总是优于OFFSET分页。

在此处,了解jOOQ如何使用SEEK子句原生支持键集分页 。

翻译自: https://www.javacodegeeks.com/2014/06/stop-trying-to-emulate-sql-offset-pagination-with-your-in-house-db-framework.html

db2分页sql

db2分页sql_停止尝试使用内部DB框架模拟SQL OFFSET分页!相关推荐

  1. 停止尝试使用内部DB框架模拟SQL OFFSET分页!

    我敢肯定,到目前为止,您已经以多种方式弄错了. 而且您可能很快将无法正确处理. 那么,当您可以实施业务逻辑时,为什么还要在SQL调整上浪费您的宝贵时间呢? 让我解释- 直到最近的SQL:2008标准 ...

  2. 分页插件pageHelpler的使用(ssm框架中)服务器端分页

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. 1. maven依赖: <!-- 分页插件 --><dependency>& ...

  3. sql server分页_SQL Server中的分页

    sql server分页 Pagination is a process that is used to divide a large data into smaller discrete pages ...

  4. javaweb解决编码问题_停止尝试编码解决问题的方法

    javaweb解决编码问题 抽象 (Abstract) Here's the situation. I need to build a test harness to verify that when ...

  5. jdbc mysql分页_JDBC【数据库连接池、DbUtils框架、分页】

    1.数据库连接池 什么是数据库连接池 简单来说:数据库连接池就是提供连接的... 为什么我们要使用数据库连接池 数据库的连接的建立和关闭是非常消耗资源的 频繁地打开.关闭连接造成系统性能低下 编写连接 ...

  6. MyBatis 分页插件 PageHelper:是如何拦截SQL进行分页

    目录 Springboot项目集成 分页插件参数介绍 如何选择配置这些参数 场景一 场景二 场景三 场景四 场景五 PageHelper的使用 PageHelper实现原理1: interceptor ...

  7. sql server分页_SQL Server中的分页简介

    sql server分页 Wikipedia Pagination is the process of dividing content (i.e. website search results, n ...

  8. 398、Java框架52 -【Hibernate - 分页、两种获取方式】 2020.10.27

    0.目录 1.分页 2.分页,从第3个开始,一共查询5个Product 3.延迟加载 4.对于id不存在的对象的处理 5.参考链接 1.分页 使用Criteria进行分页查询 无论你使用的是Oracl ...

  9. 解决hibernate对Sql Server分页慢的问题

    解决hibernate对Sql Server分页慢的问题 参考文章: (1)解决hibernate对Sql Server分页慢的问题 (2)https://www.cnblogs.com/firstd ...

最新文章

  1. 联想g400从u盘启动计算机,联想g400u盘装系统的方法
  2. (建议收藏)相对靠谱的国内大学排行榜
  3. 给年薪不到48w的程序员提个醒!!
  4. Unity开发《一起来捉妖》教程 | 4.抛掷封妖灵珠
  5. MySql大数据量恢复
  6. android 录像 源代码,android安卓视频录制摄像拍摄源码(测试可用)
  7. forEach,for in,for of循环的用法
  8. 二分图中的最大匹配数等于最小点覆盖数的证明
  9. 软件工程 第三章 需求分析
  10. PHP 省市区 最新最全json生成
  11. NIST SP800系列标准
  12. html svg 线条动画,线条之美,玩转 SVG 线条动画
  13. 检查压缩包是否损坏_【安全知识】运动安全带检查PPE(个人防护装备)检查程序与表格...
  14. dns配置异常怎么修复_电脑出现dns错误不能上网怎么办?dns错误修复方法
  15. mac系统怎么制作装系统的u盘?苹果电脑u盘启动盘制作教程
  16. 小方块上升组成背景特效 html+css+js
  17. 量子计算(七):量子系统
  18. gx works2 存储器空间或桌面堆栈不足_手机存储不够怎么办?ORICO备份宝让你拥有无限扩容空间...
  19. 信息在计算机中的表示(一)
  20. Arduino IDE 玩转STM32 - 搭环境、刷固件、烧程序

热门文章

  1. Ch3101-阶乘分解【数论,质因数分解】
  2. 【交互】【随机】Lost Root(CF1061F)
  3. Dubbo(九)之注解配置
  4. MyBatis-generator使用,Example缺少分页问题解决
  5. Spring 事务原理和使用
  6. 漫画:什么是SHA系列算法
  7. MySQL里面的in关键字
  8. css 浏览器调试中不可见_前端入门必会的初级调试技巧
  9. ROC和AUC介绍以及如何计算AUC
  10. 动手学习_动手选择值