为何UNION操作数必须是SELECT语句而非表或视图?
先看具体场景:
我们有两个结构相同的表T和S,定义如下:
CREATE TABLE "T" ("ID" INTEGER, "Salary" REAL); CREATE TABLE "S" ("ID" INTEGER, "Salary" REAL);
使用(SELECT * FROM "S") UNION (SELECT * FROM "T")可以正常实现两表联合,但直接执行"S" UNION "T"会报错:SQLite提示near "UNION": syntax error,SQL Server提示Incorrect syntax near the keyword 'UNION'。
另外,把SELECT * FROM "S"和SELECT * FROM "T"分别创建为视图view1、view2后,执行"view1" UNION "view2"同样报错:SQLite提示near "UNION": syntax error,SQL Server提示Incorrect syntax near 'view1'。
从关系代数定义来看,UNION运算符确实是以两个关系(表)为操作数输出新关系,基表、派生关系都属于关系范畴,但SQL的处理却不一样,原因如下:
SQL语法规范的硬性要求:SQL语言的语法规则明确规定,UNION这类集合运算符的操作数必须是查询表达式(Query Expression),而直接的表名或视图名并不属于查询表达式的直接写法。查询表达式的核心就是SELECT语句,哪怕是最简单的
SELECT * FROM 表名,这是SQL语法解析器的强制要求,不符合这个格式的语句会直接被判定为语法错误。关系代数与SQL实现的差异:C.J.Date的理论中,关系是抽象的概念,但SQL是一门实际的编程语言,需要明确的语法结构来让解析器识别操作逻辑。直接写表名无法让解析器明确你要对这个表执行什么操作——虽然默认是取全部数据,但SQL没有把“直接写表名”等价于“SELECT * FROM 表名”作为集合运算的合法输入,必须显式通过SELECT语句来表达“获取该表所有数据”这个操作。
视图的本质是封装的查询:视图本身并不是一个物理存储的表(除非是物化视图),它本质是一段预定义的SELECT语句。引用视图的时候,SQL需要把视图展开为对应的SELECT语句才能执行,但在集合运算中,你不能直接把视图名当作操作数,必须通过
SELECT * FROM view1这样的形式,将其转化为合法的查询表达式,才能参与UNION运算。
内容的提问来源于stack exchange,提问作者Ardy

