在PostgreSQL中子查询必须得加上别名,即使我们在其它地方不会再引用到这个别名。
否则便会报以下错误:
postgres=# select * from (select * from t1 limit 5);
ERROR: subquery in FROM must have an alias
LINE 1: select * from (select * from t1 limit 5);
^
HINT: For example, FROM (SELECT ...) [AS] foo.
而在Oracle中是可以不加别名的,例如:
SQL> select * from (select * from t1);
ID
----------
1
当然并不是说这样不好,因为PG中的这种语法是SQL标准语法,但对于某些从Oracle迁移的用户而言,可能会存在一些困扰,那么我们来看看如何从内核层面去实现兼容呢?
首先需要知道,我们输入的SQL语句是作为字符串传递给查询分析器,然后数据库对其进行词法分析和语法分析生成分析树。
而在PG中,词法分析和语法分析依赖的文件是scan.l和gram.y中。通过scan.l进行词法分析,将sql中的关键字识别,作为token传递给语法分析器,而gram.y对传入的token定义语法,并进行语法分析,从而生成parsetree。
我们根据前面的报错,找到gram.y中对应的部分:
| select_with_parens opt_alias_clause
{
RangeSubselect *n = makeNode(RangeSubselect);
n->lateral = false;
n->subquery = $1;
n->alias = $2;
/*
* The SQL spec does not permit a subselect
* (<derived_table>) without an alias clause,
* so we don't either. This avoids the problem
* of needing to invent a unique refname for it.
* That could be surmounted if there's sufficient
* popular demand, but for now let's just implement
* the spec and see if anyone complains.
* However, it does seem like a good idea to emit
* an error message that's better than "syntax error".
*/
if ($2 == NULL)
{
if (IsA($1, SelectStmt) &&
((SelectStmt *) $1)->valuesLists)
ereport(ERROR,
(errcode