18

许多 SQL 数据库支持 SQL 标准所称的<derived column list>. 此类数据库至少包括 CUBRID、Derby、Firebird、HSQLDB、Postgres、SQL Server 和 Sybase SQL Anywhere。SQL:2008 规范中的(简化的)摘录

7.6 <table reference>

Format
<table reference> ::=
    <table or query name> [ [ AS ] <correlation name>
      [ <left paren> <derived column list> <right paren> ] ]
  | <derived table> [ AS ] <correlation name>
      [ <left paren> <derived column list> <right paren> ]

这意味着,我可以表达这样的事情(例如在 Postgres 中,它非常符合标准)

-- Rename a <table or query name> to u(b)
with t(a) as (select 1)
select * from t as u(b)

-- Rename a <derived table> to u(b)
select * from (select 1) as u(b)

现在,根据Oracle 文档,我无法使用<derived column list>规范重命名列。我当然可以分别重命名表和列,如下所示:

-- Rename a <table or query name> to u(b)
with t(a) as (select 1 from dual)
select u.a b from t u;

-- Rename a <derived table> to u(b)
select u.a b from (select 1 a from dual) u;

但这比以前的语法需要更多关于派生表(实际列名)的知识。此外,重命名的列仅在投影之后可用(例如在ORDER BY子句中),而不是在任何其他子句中,包括投影本身。

在 Oracle(以及 MySQL)中,是否有更通用的方法来按照 SQL 标准建议的方式重命名表和列?特别是,这对于数组取消嵌套、透视表/取消透视表重命名、内联复杂子查询、重命名表函数的结果等可能很有用。

注意:请不要过分关注上面的例子。他们真的只是为了说明问题。现实世界的查询要复杂得多,所以我正在寻找一种非常通用的方法来实现重命名为u(b)

注意:我仍在寻找适用于 MySQL 等数据库的解决方案。一个相关问题:
如何从子选择中选择无别名的数字文字

4

3 回答 3

10

对于 MySQL 解决方案,您可以使用 aUNION设置零行查询项中所有列的名称,然后查询更复杂的内容:

SELECT null AS a, null AS b, null AS c FROM dual WHERE false
UNION ALL
SELECT <expr>, <expr>, <expr>
FROM <realtable>...

只有 UNION 的第一个查询词定义了整个查询的列名。后续查询词中的列名(或缺少列名)不会影响最终的列名。

您确实需要知道列,但是将两个查询词分开应该很容易。据我所知,它适用于 Oracle 和 MySQL(但是,我只在 MySQL 中测试过它,而不是在 Oracle 中)。

于 2013-01-07T21:24:53.717 回答
9

由于您必须知道列数,但不一定知道列名,您可以使用 WITH 子句根据需要重命名这些列。例如(WITH 适用于 Oracle 和 SQL Server,手边没有 MySQL 实例):

WITH t(x,y,z) as (select * from TABLE(fn_returning_xcols(3)))
select * from t;

这里我们不知道内部选择中的列名,但我们可以在外部 WITH 子句中重命名它们。

在 Oracle 中使用 PIVOT 的另一个示例:

WITH t(a,b,c,d,e) as 
(
 select * from 
 (
  select level as levl from dual connect by level <= 5
 )
 PIVOT(max(levl) as l for levl in (1,2,3,4,5))
)
select * from t;

同样,我们不关心内部选择列名是什么(内部枢轴创建了一些奇怪的列名),我们只需要知道有多少列就可以重命名。

于 2013-01-03T13:47:31.470 回答
0

正如用户tbone 在这里所建议的那样,公用表表达式是我的问题的一个很好的解决方案,至少对于 Oracle 而言。为了完整起见,这是我在 Oracle 中使用 CTE 编写的示例查询

-- Rename a <derived table> to u(b) with Oracle
with u(b) as (select 1 from dual) 
select u.b from u

-- Rename a <derived table> to u(b) with H2, which only knows recursive CTEs
-- Thanks to a comment by user a_horse_with_no_name
with recursive u(b) as (
  select 1
  union all
  select null where false
)
select u.b from u
于 2013-01-03T18:13:10.550 回答