PostgreSQL有意思的现象:支持不带列的表
1、前言
以前从没有试过建一张表,不带任何列。在PG中却支持这种语法。这是个什么鬼?
最近,把PG源码扒了下,简单浏览了下最近的一些merge。其中有一个fix:
eeb0ebad79 ("Fix the initial sync tables with no columns.", 2023-11-22)
Fix the initial sync tables with no columns.
The copy command formed for initial sync was using parenthesis for tables
with no columns leading to syntax error. This patch avoids adding
parenthesis for such tables.
Reported-by: Justin G
Author: Vignesh C
Reviewed-by: Peter Smith, Amit Kapila
Backpatch-through: 15
Discussion: http://postgr.es/m/18203-df37fe354b626670@postgresql.org
简单的说,是它考虑到一张表,在初始SYNC时,有可能没有任何列。按自己的印象,别的DBMS好像没有支持这种语法的。
2、简单验证
如果我们在SQLSERVER哪怕是最新版2022上试一下,
https://dbfiddle.uk/1n2I7Bj9
create table tab_no_col();
-- 立马报错
Msg 102 Level 15 State 1 Line 1
Incorrect syntax near ')'.
切到MySQL, 也不支持这种语法:
https://dbfiddle.uk/xZPbFq4N
create table tab_no_col();
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1
再试下Oracle, 发现也不支持。哪怕是23C。
https://dbfiddle.uk/-F2lutlX
create table tab_no_col();
ORA-00931: missing identifier
3、PostgreSQL中的行为
我们就以PostgreSQL 14为例 :
postgres=# create table tab_no_col();
CREATE TABLE
postgres=# insert into tab_no_col default values;
INSERT 0 1
postgres=# select * from tab_no_col;
--
(1 row)
postgres=# insert into tab_no_col default values;
INSERT 0 1
postgres=# insert into tab_no_col default values;
INSERT 0 1
postgres=# insert into tab_no_col default values;
INSERT 0 1
postgres=# select count(*) from tab_no_col;
count
-------
4
(1 row)
postgres=# select * from tab_no_col;
--
(4 rows)
虽然没有真正的值,但是却一样可以插入相关的值,并得到相应的行数。
根据这种特性,我们甚至可以预先建一张没有任何列的表,然后,插入一些列。看看:
postgres=# alter table tab_no_col add col2 varchar(32) null;
ALTER TABLE
postgres=# select * from tab_no_col;
col2
------
(4 rows)
更新一些值:
postgres=# update tab_no_col set col2 = 'a_' || ctid || '_' || xmin;
UPDATE 4
postgres=# select * from tab_no_col;
col2
-------------
a_(0,1)_785
a_(0,2)_786
a_(0,3)_787
a_(0,4)_788
(4 rows)
这种功能,也许最大的好处就是先建一张表(空列),然后可以动态的增加或改变一些列。利用FOR循环时,直接"(" 和 ”)" 做匹配,而不用考虑列数是否真正大于0。
反正CREATE TABLE ABC(), 即算完全是空的,语法上它也不会报错。