SQL*Plus BREAK 的行为如何/为啥取决于列顺序?
Posted
技术标签:
【中文标题】SQL*Plus BREAK 的行为如何/为啥取决于列顺序?【英文标题】:How / why does behavior of SQL*Plus BREAK depend on column order?SQL*Plus BREAK 的行为如何/为什么取决于列顺序? 【发布时间】:2021-11-11 05:34:53 【问题描述】:背景
我熟悉数据库,但从未特别使用过 Oracle。在尝试帮助某人完成家庭作业的过程中,我遇到了一个障碍,试图了解BREAK
命令的行为。特别是,使用BREAK
命令的结果似乎取决于我正在使用的查询中列的顺序,据我所知,这并没有以任何方式反映在文档中。
示例设置
我创建了一个表格,其中有几种不同的颜色,每种颜色都有一些该颜色的项目,如下所示:
CREATE TABLE products(product_id NUMBER, product_color VARCHAR(10), product_name VARCHAR(20));
INSERT INTO products(product_id, product_color, product_name) VALUES(1, 'Green', 'Green baseball cap');
INSERT INTO products(product_id, product_color, product_name) VALUES(2, 'Green', 'Green shirt');
INSERT INTO products(product_id, product_color, product_name) VALUES(3, 'Green', 'Grapes');
INSERT INTO products(product_id, product_color, product_name) VALUES(4, 'Orange', 'Orange baseball cap');
INSERT INTO products(product_id, product_color, product_name) VALUES(5, 'Orange', 'Traffic cone');
显示预期行为的示例
当我运行以下命令时,
CLEAR COLUMNS;
CLEAR BREAKS;
CLEAR SCREEN;
SET LINESIZE 120;
COLUMN product_color NOPRINT NEW_VALUE the_color;
BREAK ON product_color SKIP PAGE;
TTITLE CENTER the_color;
SELECT product_id, product_color, product_name FROM products ORDER BY product_color;
这似乎产生了合理的输出,每种颜色都有一个“页面”在顶部显示颜色并在下面显示相关记录:
Green
PRODUCT_ID PRODUCT_NAME
---------- --------------------
1 Green baseball cap
2 Green shirt
3 Grapes
Orange
PRODUCT_ID PRODUCT_NAME
---------- --------------------
4 Orange baseball cap
5 Traffic cone
表现出意外行为的看似相同的示例
但是,如果我只是更改查询中列的顺序,即将上面脚本的最后一行替换为以下内容:
SELECT product_color, product_id, product_name FROM products ORDER BY product_color;
那么结果就完全不同了,在每条记录之后无缘无故地生成一个分页符:
Green
PRODUCT_ID PRODUCT_NAME
---------- --------------------
1 Green baseball cap
Green
PRODUCT_ID PRODUCT_NAME
---------- --------------------
2 Green shirt
Green
PRODUCT_ID PRODUCT_NAME
---------- --------------------
3 Grapes
Orange
PRODUCT_ID PRODUCT_NAME
---------- --------------------
4 Orange baseball cap
Orange
PRODUCT_ID PRODUCT_NAME
---------- --------------------
5 Traffic cone
问题
为什么更改查询输出中的列顺序会导致与BREAK
语句不同的行为? (或者BREAK
命令是否是一个红鲱鱼,第二个示例中的分页符是出于某种不相关的原因创建的?)
这实际上是否以某种方式记录在文档中,但以某种我不理解的方式?
是否有描述这种行为的术语可供我搜索以了解更多信息?
有没有比 Oracle 官方网站更好的 SQL*Plus 文档?它似乎相当参差不齐,很少明确指定命令的作用。
可能的线索
我已经阅读了位于 https://docs.oracle.com/cd/E11882_01/server.112/e16604/ch_twelve009.htm#SQPUG030 的 SQL*Plus BREAK
命令的文档,但我没有看到任何与列出现顺序相关的内容。
我认为该问题可能与抑制干扰检测字段更改的重复项有关,但将 DUPLICATES
添加到 BREAK
命令没有任何效果。
在六种可能的排列中,导致问题的排列似乎是product_color
是第一列的两种排列。
同样,将查询更改为类似
SELECT 1, product_color, product_id, product_name FROM products ORDER BY product_color;
产生了预期的行为,这表明最左边的列可能在这里扮演了一些特殊的角色。
另外,我发现从 COLUMN
命令中删除 NOPRINT
会使这种行为消失,原因我不明白。
环境信息
oracle服务器报告它是
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production
"CORE 11.2.0.4.0 Production"
TNS for Linux: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 - Production
我正在使用 Oracle SQL Developer 版本 21.2.1.204,Build 204.1703 进行连接。
【问题讨论】:
非常好的问题。这是如何提问的一个很好的例子;)我为你的问题投票。 【参考方案1】:奇怪。我的环境和你的一样,我没有看到这样的行为。我刚刚从您发布的代码中删除了clear screen
。
这是为您(和我)返回正确结果的查询。
客户端 11.2.0.2.0
C:\Oracle\oraclexe112_64bit\app\oracle\product\11.2.0\server\bin>sqlplus scott/tiger@orcl
SQL*Plus: Release 11.2.0.2.0 Production on ╚et Stu 11 08:03:58 2021
Copyright (c) 1982, 2014, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
Data Mining and Real Application Testing options
SQL> CLEAR COLUMNS;
columns cleared
SQL> CLEAR BREAKS;
breaks cleared
SQL>
SQL> SET LINESIZE 120;
SQL>
SQL> COLUMN product_color NOPRINT NEW_VALUE the_color;
SQL> BREAK ON product_color SKIP PAGE;
SQL>
SQL> TTITLE CENTER the_color;
SQL>
SQL> SELECT product_id, product_color, product_name FROM products ORDER BY product_color;
Green
PRODUCT_ID PRODUCT_NAME
---------- --------------------
1 Green baseball cap
2 Green shirt
3 Grapes
Orange
PRODUCT_ID PRODUCT_NAME
---------- --------------------
4 Orange baseball cap
5 Traffic cone
SQL>
现在,在您的数据库中产生意外中断的查询(但在我的数据库中没有),product_color
是 select
列列表中的第一列:
SQL> SELECT product_color, product_id, product_name FROM products ORDER BY product_color;
Green
PRODUCT_ID PRODUCT_NAME
---------- --------------------
1 Green baseball cap
2 Green shirt
3 Grapes
Orange
PRODUCT_ID PRODUCT_NAME
---------- --------------------
4 Orange baseball cap
5 Traffic cone
SQL>
我也试过不同的客户端,没问题:
客户端 11.2.0.1.0
SQL*Plus: Release 11.2.0.1.0 Production on ╚et Stu 11 08:10:56 2021
SQL> CLEAR COLUMNS;
columns cleared
SQL> CLEAR BREAKS;
breaks cleared
SQL>
SQL> SET LINESIZE 120;
SQL>
SQL> COLUMN product_color NOPRINT NEW_VALUE the_color;
SQL> BREAK ON product_color SKIP PAGE;
SQL>
SQL> TTITLE CENTER the_color;
SQL>
SQL> SELECT product_color, product_id, product_name FROM products ORDER BY product_color;
Green
PRODUCT_ID PRODUCT_NAME
---------- --------------------
1 Green baseball cap
2 Green shirt
3 Grapes
Orange
PRODUCT_ID PRODUCT_NAME
---------- --------------------
4 Orange baseball cap
5 Traffic cone
SQL>
客户端 18.5.0.0.0
SQL*Plus: Release 18.0.0.0.0 - Production on Thu Nov 11 08:12:20 2021
Version 18.5.0.0.0
SQL> CLEAR COLUMNS;
columns cleared
SQL> CLEAR BREAKS;
breaks cleared
SQL>
SQL> SET LINESIZE 120;
SQL>
SQL> COLUMN product_color NOPRINT NEW_VALUE the_color;
SQL> BREAK ON product_color SKIP PAGE;
SQL>
SQL> TTITLE CENTER the_color;
SQL>
SQL> SELECT product_color, product_id, product_name FROM products ORDER BY product_color;
Green
PRODUCT_ID PRODUCT_NAME
---------- --------------------
1 Green baseball cap
2 Green shirt
3 Grapes
Orange
PRODUCT_ID PRODUCT_NAME
---------- --------------------
4 Orange baseball cap
5 Traffic cone
SQL>
我认为这是至关重要的:
我正在使用 Oracle SQL Developer 版本 21.2.1.204,Build 204.1703 进行连接。
SQL 开发人员。我和 Roberto 使用了 Oracle 的命令行工具 SQL Plus。
当我测试您返回“无效”结果的代码时,这是真的!
columns cleared
breaks cleared
Green
PRODUCT_ID PRODUCT_NAME
---------- --------------------
1 Green baseball cap
Green
PRODUCT_ID PRODUCT_NAME
---------- --------------------
2 Green shirt
Green
PRODUCT_ID PRODUCT_NAME
---------- --------------------
3 Grapes
Orange
PRODUCT_ID PRODUCT_NAME
---------- --------------------
4 Orange baseball cap
Orange
PRODUCT_ID PRODUCT_NAME
---------- --------------------
5 Traffic cone
SQL Developer 会产生“错误”的结果。它与数据库版本无关,而是工具。
那么,该怎么办?请改用 SQL*Plus :) 或者,下载 SQLcl,这是 Oracle 提供的最新命令行工具。
【讨论】:
抓得好!我更新了指向您的 cmets 的答案。我在问题本身中依赖于 sqlplus 的链接,所以我假设他正在使用 sqlplus。该工具后来在我写答案时进行了编辑。很高兴知道你一直在这里,我的朋友;) 啊,所以 SQL*Plus 是 工具 的名称,而不是 语言,以及像COLUMN
和 BREAK
这样的命令等等都是在客户端运行的?
没错,@Daniel。语言是“SQL”。工具是 SQL Plus。顺便说一句,为了让你免于进一步的痛苦,我刚刚安装了 SQLcl,这样你就不必安装了。它也会产生“错误”的结果,所以 - 唯一的出路是安装 SQL Plus(或使用您已经找到的解决方法查询)。【参考方案2】:
BREAK
在您的示例中的行为不正确。感谢@Littlefoot,我更新了这篇文章,这是因为您使用的是 SqlDeveloper,这是一个不用于此类报告的 Java 工具。
我创建了您的表格并将记录插入到两个数据库中,然后运行您所做的报告。
演示 12cR2
SQL> select banner from v$version ;
BANNER
--------------------------------------------------------------------------------
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
PL/SQL Release 12.2.0.1.0 - Production
CORE 12.2.0.1.0 Production
TNS for Linux: Version 12.2.0.1.0 - Production
NLSRTL Version 12.2.0.1.0 - Production
SQL> CREATE TABLE products(product_id NUMBER, product_color VARCHAR(10), product_name VARCHAR(20));
Table created.
INSERT INTO products(product_id, product_color, product_name) VALUES(1, 'Green', 'Green baseball cap');
1 row created.
INSERT INTO products(product_id, product_color, product_name) VALUES(2, 'Green', 'Green shirt');
1 row created.
INSERT INTO products(product_id, product_color, product_name) VALUES(3, 'Green', 'Grapes');
1 row created.
INSERT INTO products(product_id, product_color, product_name) VALUES(4, 'Orange', 'Orange baseball cap');
1 row created.
SQL> INSERT INTO products(product_id, product_color, product_name) VALUES(5, 'Orange', 'Traffic cone');
1 row created.
现在让我们运行报告
SQL> CLEAR COLUMNS;
columns cleared
SQL> CLEAR breaks;
breaks cleared
SQL> COLUMN product_color NOPRINT NEW_VALUE the_color;
SQL> BREAK ON product_color SKIP PAGE;
SQL> TTITLE CENTER the_color;
SQL> SELECT product_id, product_color, product_name FROM products ORDER BY product_color;
Green
PRODUCT_ID PRODUCT_NAME
---------- --------------------
1 Green baseball cap
2 Green shirt
3 Grapes
Orange
PRODUCT_ID PRODUCT_NAME
---------- --------------------
4 Orange baseball cap
5 Traffic cone
SQL> SELECT product_color, product_id, product_name FROM products ORDER BY product_color;
Green
PRODUCT_ID PRODUCT_NAME
---------- --------------------
1 Green baseball cap
2 Green shirt
3 Grapes
Orange
PRODUCT_ID PRODUCT_NAME
---------- --------------------
4 Orange baseball cap
5 Traffic cone
如您所见,在 12.2 中,BREAK
命令中没有意外行为,它可以正常工作。
演示 19c
SQL> select banner_full from v$version ;
BANNER_FULL
------------------------------------------------------------------------------------------------------------------------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.6.0.0.0
SQL> CREATE TABLE products(product_id NUMBER, product_color VARCHAR(10), product_name VARCHAR(20));
Table created.
INSERT INTO products(product_id, product_color, product_name) VALUES(1, 'Green', 'Green baseball cap');
1 row created.
INSERT INTO products(product_id, product_color, product_name) VALUES(2, 'Green', 'Green shirt');
1 row created.
INSERT INTO products(product_id, product_color, product_name) VALUES(3, 'Green', 'Grapes');
1 row created.
INSERT INTO products(product_id, product_color, product_name) VALUES(4, 'Orange', 'Orange baseball cap');
1 row created.
SQL> INSERT INTO products(product_id, product_color, product_name) VALUES(5, 'Orange', 'Traffic cone');
1 row created.
现在,让我们运行报告
SQL> CLEAR COLUMNS;
columns cleared
SQL> CLEAR BREAKS;
breaks cleared
SQL> COLUMN product_color NOPRINT NEW_VALUE the_color;
SQL> BREAK ON product_color SKIP PAGE;
SQL> TTITLE CENTER the_color;
SQL> SELECT product_id, product_color, product_name FROM products ORDER BY product_color;
Green
PRODUCT_ID PRODUCT_NAME
---------- --------------------
1 Green baseball cap
2 Green shirt
3 Grapes
Orange
PRODUCT_ID PRODUCT_NAME
---------- --------------------
4 Orange baseball cap
5 Traffic cone
SQL> SELECT product_color, product_id, product_name FROM products ORDER BY product_color;
Green
PRODUCT_ID PRODUCT_NAME
---------- --------------------
1 Green baseball cap
2 Green shirt
3 Grapes
Orange
PRODUCT_ID PRODUCT_NAME
---------- --------------------
4 Orange baseball cap
5 Traffic cone
因此,BREAK
命令的预期行为相同。
回答您的问题
为什么更改查询输出中列的顺序会导致与BREAK
语句不同的行为? (或者BREAK
命令是一个红鲱鱼,第二个示例中的分页符是出于某种不相关的原因创建的?)
不会。 正如我之前所说,这种行为在 12c 和 19c 中都无法重现(如@Littlefoot 所示,在 11g 中无法重现)。我向您保证BREAK
的正常行为不受订单影响。
这实际上是否以某种方式记录在文档中,但以某种我不理解的方式?
不是,因为您了解命令的工作原理,但不了解您所获得的行为,这显然无法在 12c 或更高版本中重现。我无法在 11g 中进行任何测试,因为这是一个非常旧且不受支持的版本,但在 @Littlefoot 的另一个答案中,您可以看到行为是相同的。
有没有比 Oracle 官方网站更好的 SQL 文档?它似乎相当参差不齐,很少明确指定命令的作用。*
参考是你能找到的最好的。显然,甲骨文和其他所有主要的软件供应商一样,并不是完美的文档。老实说,我不能为此责怪他们,因为它无处不在。实际上,我确实认为他们拥有最好的之一。
我的建议:使用sqlplus
并升级您的数据库。 11g 几年前就被弃用了。你可以试试sqlcl
sql developer 命令行界面,不过我没用过11g,虽然我觉得应该没问题
顺便说一句,关于我发现从 COLUMN 命令中删除 NOPRINT 会使这种行为消失,原因我不明白。
PRINT|NOPRINT 控制列的打印(列标题和所有 选定的值)。 NOPRINT 关闭屏幕输出和打印 列。 PRINT 打开列的打印。
不完全是。如果您将NOPRINT
更改为PRINT
,它将正常工作,以便您可以打印属于BREAK
的列。但是,它只在结果中显示一次,因为你打破了它。
SQL> COLUMN product_color PRINT NEW_VALUE the_color;
SQL> SELECT product_id, product_color, product_name FROM products ORDER BY product_color;
Green
PRODUCT_ID PRODUCT_CO PRODUCT_NAME
---------- ---------- --------------------
1 Green Green baseball cap
2 Green shirt
3 Grapes
Orange
PRODUCT_ID PRODUCT_CO PRODUCT_NAME
---------- ---------- --------------------
4 Orange Orange baseball cap
5 Traffic cone
希望这个长长的答案能以某种方式帮助您。随时提出您可能有的任何问题或疑问。但我很确定原因是你的版本。
更新
正如@Littlefoot 在下面的回答中所述,该问题可能与 SQLDeveloper 有关,它是一种 Java 工具。我没有意识到您使用的是 SQL Developer,即使您可以运行脚本,但对于那些 sqlplus
特定的报告命令来说,它是不一样的。我依赖于您的文档链接到sqlplus
,所以我自然假设您正在使用它。
【讨论】:
不幸的是,这个 11g 实例是学校提供的,需要作业来对抗它。但知道这可能是近十年前已弃用的数据库版本中的一个错误,这是值得了解的信息。 @DanielMcLaury,另一个选项(我刚刚更新)是安装客户端 12c 并连接到 11g 数据库。然而,无论如何,学校不应该这样做。他们必须升级,我的意思是他们正在教学,所以他们应该是最新的 也就是说,回复:我在日常工作中习惯了更多详细信息的文档。比较 C++ 标准或 Java 或 .NET 的官方文档。它们的编写方式都可以让您在纸上模拟程序的行为并对结果有 100% 的信心。 我认为尝试在客户端做一些事情可能是不行的,因为当评分者尝试使用学校的客户端运行代码时,它可能无法正常工作。 无论如何,我只想再说一遍,我希望有人能把你的问题作为如何提问的例子。为此,我花时间调查两个不同数据库中的行为,并努力将所有这些都放在答案中。 #以上是关于SQL*Plus BREAK 的行为如何/为啥取决于列顺序?的主要内容,如果未能解决你的问题,请参考以下文章
获取 SQL 执行计划。 PL/SQL Developer = 奇怪的行为。 SQL*Plus = 未选择任何行
为啥我不断收到这个受诅咒的 SQL*Plus 无效标识符错误?
为啥 Oracle Sql*Plus 打印许多不需要的标题?