Только что натолкнулся на возможность Postgresql, показавшуюся мне забавной. Для кого "баян" — респект вам, я несколько лет работаю с Postgres и до сих пор не натыкался на такую штуку.
select;
без указания полей, таблицы и условий возвращает одну строку. Но у этой строки нет полей:
=> select;
--
(1 row)
Для сравнения:
=> select null;
?column?
----------
(1 row)
=> select null where 0=1;
?column?
----------
(0 rows)
А сможем ли мы создать таблицу из такого "пустого" запроса? Таблицу без полей.
Да пожалуйста:
=> create table t as select;
SELECT 1
=> \d+ t
Table "t"
Column | Type | Modifiers | Storage | Stats target | Description
--------+------+-----------+---------+--------------+-------------
=> select * from t;
--
(1 row)
А можем ли мы в неё вставить?
Легко:
=> insert into t select;
INSERT 0 1
=> insert into t select;
INSERT 0 1
=> select * from t;
--
(3 rows)
=> select count(*) from t;
count
-------
3
ЕЩЕ!
=> insert into t select from generate_series(1,1000000);
INSERT 0 1000000
Интересно, будет ли Postgresql сканировать такую таблицу?
=> explain analyze select * from t;
QUERY PLAN
------------------------------------------------------------------------------------------------------------
Seq Scan on t (cost=0.00..13438.67 rows=1000167 width=0) (actual time=0.018..96.389 rows=1000003 loops=1)
Planning time: 0.024 ms
Execution time: 134.654 ms
(3 rows)
Да, честно сканирует. Больше 100 ms — вполне себе заметное время.
Ну и чтобы убедиться, что всё по честному, посмотрим сколько места занимает наша супер-полезная таблица:
=> select pg_size_pretty(pg_total_relation_size('t'));
pg_size_pretty
----------------
27 MB
(1 row)
То есть таблица есть, занимает место на диске, в блоках хранятся разные служебные данные, ну а то, что в ней нет полей — бывает, дело житейское!
=> select t.xmin, t.ctid from t limit 10;
xmin | ctid
---------+--------
1029645 | (0,1)
1029647 | (0,2)
1029648 | (0,3)
1029649 | (0,4)
1029649 | (0,5)
1029649 | (0,6)
1029649 | (0,7)
1029649 | (0,8)
1029649 | (0,9)
1029649 | (0,10)
(10 rows)
Я не придумал, зачем может понадобиться такая таблица. Но возможность есть, и это хорошо!
Я использую Postgresql 9.6. Как отмечают ниже в более низких версиях это не работает. В 9.3 выдаёт syntax error
. 9.4, 9.5 под рукой нет чтобы проверить.
Комментарии (33)
spendlively
31.05.2017 09:46+13Для кого «боян»...
Правильно писать «бАян»! Извините, не смог, сдержаться. Просто 8 лет играл на нем в школе. Наконец-то пригодилось!fireSparrow
31.05.2017 10:06+5Из википедии:
Боян (Boian) — археологическая культура эпохи неолита (4-е тыс. до. н. э.), на территории Молдавии, Румынии и Болгарии.
То есть, когда про какую-то тему говорят «ну, это уже боян», значит этой теме 5-6 тысяч лет.KozzyKoder
31.05.2017 11:42+1Еще в «Слове о полку Игореве» упоминается древнерусский певец и сказитель Боян. Всегда думал что это слово с ним связано.
dmitry_dvm
31.05.2017 11:35В этом контексте как раз таки боян, а не баян. Т.к. автор имел в виду нечто давно известное, а не музыкальный инструмент.
fireSparrow
31.05.2017 11:53+2На самом деле, всё-таки «баян».
Существуют три основных версии, почему это слово стали использовать в значении «повторно опубликованная шутка или информация».
По двум из них это слово как раз-таки пошло от названия музыкального инструмента, по третьей — от крейсера «Баян» времён русско-японской войны.Razoomnick
31.05.2017 15:50+1Я всегда почему-то думал, что это отсылка к анекдоту «хоронили тещу, порвали два баяна».
fireSparrow
31.05.2017 15:58Да, это как раз таки самая популярная версия.
Считается, что на неком форуме этот анекдот постили настолько часто, что в итоге он начал вызывать резко негативную реакцию у старожилов, они-то и начали употреблять слово «баян» в современном значении.
Но есть и другие версии.
ploop
31.05.2017 09:55У меня одного данный пример возвращает только syntax error?
CPro
31.05.2017 11:21Добавил комментарий про версию. В 9.3 не работает, в 9.5, говорят, работает. Осталось проверить 9.4 у кого есть и мы будем знать мажорную версию, когда добавили эту супер фишку :)
Ну не читать же release notes, в самом деле :)kshvakov
31.05.2017 12:40+4Это появилось в 9,4
https://www.postgresql.org/docs/9.4/static/release-9-4.html
Allow SELECT to have an empty target list (Tom Lane)
This was added so that views that select from a table with zero columns can be dumped and restored correctly.CPro
31.05.2017 12:45+1О, ты наш герой! Думал уж никто до release notes не доберётся :)
То что там написано как то не очень пролило свет:
This was added so that views that select from a table with zero columns can be dumped and restored correctly.
Ну ок, чтобы работал дамп и рестор вьюх на таблицы без колонок. А зачем нужны вьюхи которые селектят из таблицы без колонок? Зачем вообще эти таблицы?
kshvakov
31.05.2017 12:38Это из-за того, что до версии 9,4 нельзя было делать SELECT без указания колонок; например для EXISTS приходилось ставить null (SELECT * FROM T WHERE f EXISTS (SELECT null FROM ...), сейчас это не обязательно
CPro
31.05.2017 12:41Это точно, или предположение? Всё ради того, чтобы сэкономить на наборе 5 символов?
Movimento5Litri
31.05.2017 12:24=> select pg_size_pretty(pg_total_relation_size('t'));
pg_size_pretty
— 27 MB
А почему так много?
guai
31.05.2017 18:10+1Хорошая, годная фича. Сделал пустую таблицу, потом напихал в нее колонок — красота. То же самое при удалении, все удалил, нужные создал. Иначе был бы головняк с последней колонкой — сделай колонку затычку, чтоб не ругалось, потом удали — ужос.
excoder
01.06.2017 00:37Это классика реляционной алгебры. Dee и Dum Дэйта:
[Dee] is the relation that has no attributes and a single tuple. It plays the role of True.
[Dum] is the relation that has no attributes and no tuples. It plays the role of False.
Отсюда: https://www.amazon.com/Foundation-Future-Database-Systems-Manifesto/dp/0201709287.
zoroda
Это особенность реализации для ALTER TABLE, чтобы при очередном DROP COLUMN не валилась ошибка
CPro
Тоже странная вещь ведь. По-сути это как новую таблицу сделать, если все поля дропаешь и новые добавляешь.
zoroda
Да, наверное странно, но такое решение было принято чтобы обойти потенциальные проблемы с DROP COLUMN