英文:
oracle sql union order by
问题
这是一个关于认证的问题,涉及到案例A和案例B。为什么案例B可以运行,但案例A不能运行?
案例A(不工作):
select col_a, col_b, 'b' from table_a
union
select col_a, col_b, 'a' from table_a
order by 'b';
案例B(工作):
select col_a, col_b, 'b' from table_a order by 'b';
英文:
This is a certification question case A and case B, why it works in case B, but doesn't work in case A
case A (not working)
select col_a, col_b, 'b' from table_a
union
select col_a, col_b, 'a' from table_a
order by 'b';
case B (working)
select col_a, col_b, 'b' from table_a order by 'b';
答案1
得分: 2
你正在使用字符串字面量 'a'
进行数据排序,这与任何其他字符串字面量一样,例如 'Littlefoot'
,两者都是无用的,但是是允许的:
SQL> select dname, 'a' from dept order by 'a';
DNAME '
ACCOUNTING a
RESEARCH a
SALES a
OPERATIONS a
SQL> select dname, 'a' from dept order by 'Littlefoot';
DNAME '
ACCOUNTING a
RESEARCH a
SALES a
OPERATIONS a
SQL>
order by
子句 - 用于 union
查询 - 适用于由该联合返回的整个数据集:
SQL> select dname, 'a' from dept where deptno <= 20
2 union
3 select dname, 'b' from dept where deptno > 20
4 order by dname;
DNAME '
ACCOUNTING a
OPERATIONS b
RESEARCH a
SALES b
SQL>
正如您已经知道的,按字符串字面量排序在这种情况下不起作用:
SQL> select dname, 'a' from dept where deptno <= 20
2 union
3 select dname, 'b' from dept where deptno > 20
4 order by 'Littlefoot';
order by 'Littlefoot'
*
ERROR at line 4:
ORA-01785: ORDER BY item must be the number of a SELECT-list expression
这个错误字面意思是:
> 您尝试执行一个包含 ORDER BY 子句的 SELECT 语句,该子句引用了不与您的 SELECT 列表中的有效列对应的列号。
正如您已经被告知的,您可以使用别名或列的位置,或者将该 union
用作子查询,然后再应用字符串字面量排序 - 在这种情况下,它将(再次)起作用:
SQL> select *
2 from (select dname, 'a' from dept where deptno <= 20
3 union
4 select dname, 'b' from dept where deptno > 20
5 )
6 order by 'Littlefoot';
DNAME '
ACCOUNTING a
OPERATIONS b
RESEARCH a
SALES b
SQL>
这是无用的(与以前一样),但是允许的。
人们希望像这样的东西能够起作用(通过隐式数据转换,Oracle 将字符串 '2'
(字符串)转换为 2
(数字)并按位置排序),但是 - 不起作用:
SQL> select dname, 'a' from dept where deptno <= 20
2 union
3 select dname, 'b' from dept where deptno > 20
4 order by '2';
order by '2'
*
ERROR at line 4:
ORA-01785: ORDER BY item must be the number of a SELECT-list expression
位置排序当然可以使用:
SQL> select dname, 'a' from dept where deptno <= 20
2 union
3 select dname, 'b' from dept where deptno > 20
4 order by 2;
DNAME '
RESEARCH a
ACCOUNTING a
SALES b
OPERATIONS b
SQL>
因此,我怀疑是 union
引起了问题。也许问题在于 UNION
返回了 DISTINCT
数据集,并且在其中 - ORDER BY
子句不能引用不是 SELECT
列列表的列,字面意义上如此。
英文:
You're sorting data by a string literal, 'a'
which is as good as any other string literal, such as 'Littlefoot'
: both are useless, but are allowed:
SQL> select dname, 'a' from dept order by 'a';
DNAME '
-------------- -
ACCOUNTING a
RESEARCH a
SALES a
OPERATIONS a
SQL> select dname, 'a' from dept order by 'Littlefoot';
DNAME '
-------------- -
ACCOUNTING a
RESEARCH a
SALES a
OPERATIONS a
SQL>
order by
clause - applied to union
ed queries - works for the whole data set returned by that union:
SQL> select dname, 'a' from dept where deptno <= 20
2 union
3 select dname, 'b' from dept where deptno > 20
4 order by dname;
DNAME '
-------------- -
ACCOUNTING a
OPERATIONS b
RESEARCH a
SALES b
SQL>
As you already know, sorting by string literal won't work in this case:
SQL> select dname, 'a' from dept where deptno <= 20
2 union
3 select dname, 'b' from dept where deptno > 20
4 order by 'Littlefoot';
order by 'Littlefoot'
*
ERROR at line 4:
ORA-01785: ORDER BY item must be the number of a SELECT-list expression
SQL>
That error literally means:
> You tried to execute a SELECT statement that included a ORDER BY clause that referenced a column number that did not correspond to a valid column in your SELECT list.
As you were already told, you could use an alias or column's position, or use that union
as a subquery and then apply sorting by a string literal - in that case, it'll (again) work:
SQL> select *
2 from (select dname, 'a' from dept where deptno <= 20
3 union
4 select dname, 'b' from dept where deptno > 20
5 )
6 order by 'Littlefoot';
DNAME '
-------------- -
ACCOUNTING a
OPERATIONS b
RESEARCH a
SALES b
SQL>
That's useless (as it was before), but it is allowed.
One could hope that something like this would work ("hope" by means of implicit data conversion, where Oracle would convert '2'
(a string) to 2
(a number) and sort by position), but - nope:
SQL> select dname, 'a' from dept where deptno <= 20
2 union
3 select dname, 'b' from dept where deptno > 20
4 order by '2';
order by '2'
*
ERROR at line 4:
ORA-01785: ORDER BY item must be the number of a SELECT-list expression
Positional sorting works, of course:
SQL> select dname, 'a' from dept where deptno <= 20
2 union
3 select dname, 'b' from dept where deptno > 20
4 order by 2;
DNAME '
-------------- -
RESEARCH a
ACCOUNTING a
SALES b
OPERATIONS b
SQL>
Therefore, I suspect that it is the union
that causes problems. Maybe it is about the fact that UNION
returns DISTINCT
data set, and - with it - ORDER BY
clause can't refer columns that aren't part of the SELECT
column list, literally.
答案2
得分: 1
'b'
是一个字符串文字,而不是列的标识符(因为列的标识符是用引号括起来的 "'B'"
)。
您可以使用列编号:
select col_a, col_b, 'b' from table_a union
select col_a, col_b, 'a' from table_a
order by 3;
或者使用带引号的标识符并将文字转换为大写:
select col_a, col_b, 'b' from table_a union
select col_a, col_b, 'a' from table_a
order by "'B'";
或者为列设置一个别名并使用它:
select col_a, col_b, 'b' AS b from table_a union
select col_a, col_b, 'a' from table_a
order by b;
请参阅 SELECT
文档
集合运算符: UNION, UNION ALL, INTERSECT, MINUS
[...]
order_by_clause
使用
ORDER BY
子句对语句返回的行进行排序。如果没有 order_by_clause,则不能保证多次执行相同查询会以相同的顺序检索行。[...]
expr
expr 根据其对 expr 的值对行进行排序。表达式基于 select 列表中的列或
FROM
子句中的表、视图或物化视图中的列。[...]
ORDER BY
子句的限制
ORDER BY
子句有以下限制:
- 如果在此语句中指定了
DISTINCT
操作符,则此子句不能引用列,除非它们出现在 select 列表中。
您正在使用 UNION
(而不是 UNION ALL
),它隐含地应用了 DISTINCT
操作符,因此限制适用于您“引用列,除非它们出现在 select 列表中”。在 select 列表中,列的标识符是用引号括起来的 "'B'"
,而不是字符串文字 'b'
(也不是字符串文字 'B'
),您需要将其视为列标识符(或按照 select 列表中的位置或使用别名引用它)。
注意:即使不考虑隐含的 DISTINCT
附加限制,UNION
查询的基本限制是“该表达式基于 select 列表中的列或 FROM
子句中的表、视图或物化视图中的列”,而文字 'b'
不是 select 列表中的列,也不来自 FROM
子句的对象,因此如果使用 UNION ALL
而不是 UNION
,它将是有效的。
英文:
'b'
is a string literal and not an identifier for the column (as the identifier for the column is the quoted identifier "'B'"
).
You can either use the column number:
select col_a, col_b, 'b' from table_a union
select col_a, col_b, 'a' from table_a
order by 3;
or use a quoted identifier and convert the literal to upper-case:
select col_a, col_b, 'b' from table_a union
select col_a, col_b, 'a' from table_a
order by "'B'";
or give the column an alias and use that:
select col_a, col_b, 'b' AS b from table_a union
select col_a, col_b, 'a' from table_a
order by b;
See the SELECT
documentation
> ### Set Operators: UNION, UNION ALL, INTERSECT, MINUS
>
> [...]
>
> #### order_by_clause
>
> Use the ORDER BY
clause to order rows returned by the statement. Without an order_by_clause, no guarantee exists that the same query executed more than once will retrieve rows in the same order.
>
> [...]
>
> expr
>
> expr orders rows based on their value for expr. The expression is based on columns in the select list or columns in the tables, views, or materialized views in the FROM
clause.
>
> [...]
>
> ### Restrictions on the ORDER BY
Clause
>
> The following restrictions apply to the ORDER BY
clause:
>
> - If you have specified the DISTINCT
operator in this statement, then this clause cannot refer to columns unless they appear in the select list.
You are using UNION
(and not UNION ALL
) which is implicitly applying the DISTINCT
operator so the restriction applies that you "refer to columns unless they appear in the select list." The identifier for the column in the select list is the quoted identifier "'B'"
and not the string literal 'b'
(and also not the string literal 'B'
) and you need to refer to it as that (or by the position in the select list or by an alias).
Note: Even without applying the additional restriction from the implicit DISTINCT
, the base restriction for UNION
queries is "The expression is based on columns in the select list or columns in the tables, views, or materialized views in the FROM
clause" and the literal 'b'
is not a column in the select list or from an object of the FROM
clause so it would be valid if you used UNION ALL
instead of UNION
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论