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_colorselect 列列表中的第一列:

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 是 工具 的名称,而不是 语言,以及像 COLUMNBREAK 这样的命令等等都是在客户端运行的? 没错,@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 打印许多不需要的标题?

谁能告诉我为啥会收到 SQL*PLUS 无效标识符错误?

为啥 SQL Developer 与 SQL Plus 中的 Oracle PL/SQL 响应时间存在差异?

为啥即使使用提交后 sql plus 也不会保存新行?