Home > Software engineering >  How / why does behavior of SQL*Plus BREAK depend on column order?
How / why does behavior of SQL*Plus BREAK depend on column order?

Time:11-12

Background

I'm familiar with databases but have never used Oracle in particular. In the process of trying to help someone with a homework assignment, I've hit a snag trying to understand the behavior of the BREAK command. In particular, the results of using the BREAK command seem to depend on the order of the columns in the query I'm using, which as far as I can tell is not reflected in the documentation in any way.

Setup for examples

I created a table where there are a couple of different colors, each with a few items of that color, like so:

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');

Example displaying expected behavior

When I run the following commands,

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;

This appears to produce reasonable output, with one "page" per color showing the color at the top and showing the relevant records below:

                                                        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        

Seemingly-identical example exhibiting unexpected behavior

However, if I simply change the order of the columns in the query, i.e. replacing the last line of the script above with something like:

SELECT product_color, product_id, product_name FROM products ORDER BY product_color;

then the results are completely different, generating a page break after every single record for no apparent reason:

                                                        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

Questions

  • Why does changing the order of the columns in the query output result in different behavior from the BREAK statement? (Or is the BREAK command a red herring, with the page breaks in the second example being created for some unrelated reason?)
  • Is this actually documented somehow in the documentation, but in some way that I'm not understanding?
  • Is there a term describing this behavior that I can search for to read more?
  • Is there any better documentation for SQL*Plus than the official Oracle site? It seems to be fairly spotty and rarely to unambiguously specify what the commands do.

Possible leads

I have read through the documentation for the SQL*Plus BREAK command located at https://docs.oracle.com/cd/E11882_01/server.112/e16604/ch_twelve009.htm#SQPUG030 but I'm not seeing anything relevant to the order that columns appear in.

I thought the issue might potentially have something to do with suppression of duplicates interfering with the detection of the field changing, but adding DUPLICATES to the BREAK command has no effect.

Of the six possible permutations, it looks like the ones that cause a problem are the two where product_color is the first column.

Similarly, changing the query to something like

SELECT 1, product_color, product_id, product_name FROM products ORDER BY product_color;

produces the expected behavior, suggesting that perhaps the leftmost column plays some special role here.

Also, I have discovered that removing NOPRINT from the COLUMN command makes this behavior go away, for reasons I don't understand.

Environment information

The oracle server reports that it is

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

I am using Oracle SQL Developer version 21.2.1.204, Build 204.1703 to connect.

CodePudding user response:

Strange. My environment is just the same as yours, and I don't see such a behaviour. I just removed clear screen from code you posted.

This is query that returns correct result for you (and for me).

Client 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>

Now, query that produces unexpected breaks in your database (but doesn't in mine), with product_color being the 1st column in select column list:

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>

I tried different clients as well, no problem:

Client 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>

Client 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>

I believe that this is crucial:

I am using Oracle SQL Developer version 21.2.1.204, Build 204.1703 to connect.

SQL Developer. Me and Roberto used SQL Plus, Oracle's command-line tool.

When I tested your code that returns "invalid" result, so true!

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        

It is SQL Developer that produces "wrong" result. It has nothing to do with the database version, but the tool.

So, what to do? Use SQL*Plus instead :) Or, download SQLcl, the newest command-line tool Oracle provides.

CodePudding user response:

The behaviour of BREAK in your example is not right. I update this post thanks to @Littlefoot, and is due to the fact that you are using a SqlDeveloper, a java tool not intended for this kind of reporting.

I created your table and insert the records in both databases, then running the reports you did.

Demo 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.

Now let's run the reports

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

As you have seen, in 12.2 there is no unexpected behaviour in the BREAK command and it works as it should.

Demo 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.

Now, let's run the reports

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

So, same expected behaviour of the BREAK command.

Answering your questions

Why does changing the order of the columns in the query output result in different behaviour from the BREAK statement? (Or is the BREAK command a red herring, with the page breaks in the second example being created for some unrelated reason?)

It does not. As I said before, such behaviour can't be reproduced neither in 12c nor 19c ( not in 11g as @Littlefoot shown ). I assure you that the normal behaviour of BREAK is not affected by the order.

Is this actually documented somehow in the documentation, but in some way that I'm not understanding?

Not really, as you understands how the command works but not the behaviour you are getting, which clearly is not reproducible in 12c or higher versions. I have no option to test nothing in 11g as that's a very old and unsupported version, but in the other answer from @Littlefoot, you can see that the behaviour is the same.

Is there any better documentation for SQLPlus than the official Oracle site? It seems to be fairly spotty and rarely to unambiguously specify what the commands do.*

The reference is the best you can find. Obviously, Oracle, as every other major software provider, is not perfect documenting. I can't blame them for that, honestly, as it happens everywhere. Actually, I do think they have one of the best ones.

My advice: Use sqlplus and Upgrade your database. 11g was deprecated years ago. You can try with sqlcl the sql developer command line interface, but I never used against 11g, although I do think it should not be a problem

By the way, regarding I have discovered that removing NOPRINT from the COLUMN command makes this behaviour go away, for reasons I don't understand.

PRINT|NOPRINT Controls the printing of the column (the column heading and all the selected values). NOPRINT turns off the screen output and printing of the column. PRINT turns the printing of the column ON.

Not exactly. If you change NOPRINT by PRINT, it works as it should, so that you might print the column that is part of the BREAK. But, it only shows once in the results, because you break on it.

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

Hope this long answer help you somehow. Feel free to ask any question or doubt you might have. But I am quite sure that the reason is your version.

UPDATE

As @Littlefoot as stated in his answer below, the issue might be related with SQLDeveloper, which is a Java tool. I did not realize you were using SQL Developer, even though you can run scripts, it is not the same for those sqlplus specific reporting commands. I was relying in your documentation links to sqlplus, so naturally I assume you were using it.

  • Related