Этот сайт — моя персональная записная книжка. Интересна мне, по большей части, история, своя жизнь и немного программирование.

«99 бутылок» и «Постгрес»

Недавно моему сайту исполнилось 25 лет и я вспоминал свою первую заметку, с которой всё началось. Она положила начало традиции, которая длится столько, сколько существует этот сайт — писать «песню о пиве», это такая американская считалочка, на различных языках программирования.

Когда я пересматривал ту заметку, обратил внимание насколько сложно написана была «песня о пиве» на языке СУБД «Постгрес». Это был 2000-й год, седьмая версия, не исключено что тогда проще было и нельзя. Но прошедшие десятилетия «Постгрес» сильно изменился, хочу показать насколько проще можно сейчас написать то же самое:

(
    WITH phrase(ph) AS (
        SELECT COALESCE(NULLIF(beer, 0)::text, 'no') || ' bottle' ||
            CASE beer WHEN 1 THEN '' ELSE 's' END || ' of beer'
        FROM generate_series(99, 0, -1) AS c(beer)
    )
    SELECT ph || ' on the wall, ' || ph || '.' || e'\n' ||
        'Take one down and pass it around, ' ||
        LEAD(ph) OVER() || e' on the wall.\n' AS " "
    FROM phrase LIMIT 99
)
UNION ALL SELECT
'No more bottles of beer on the wall, no more bottles of beer.
Go to the store and buy some more, 99 bottles of beer on the wall.';
4 комментария
Евгений 24 дн

format() упрощает конкатенацию (надеюсь, что форматирование не съест ничего):

select format(
e’%1$s bottle%3$s of beer on the wall, %1$s bottle%3$s of beer.\nTake one down and pass it around, %2$s bottles of beer on the wall.’,
i, case (i — 1) when 0 then ’no’ else (i — 1)::text end, (array [’s’])[(i — 1)::bool::int]
)
from generate_series(99, 1, -1) as bc(i)
union all
select ’No more bottles of beer on the wall, no more bottles of beer.
Go to the store and buy some more, 99 bottles of beer on the wall.’;

Евгений Степанищев 23 дн

Мне кажется у меня всё-таки больше в стиле SQL :-) Я, когда пишу код, стараюсь написать в той манере, в которой пишут на языке, плюс, если это возможно, показать какие-то особенности.

Евгений 24 дн

Апострофы поменяло на одинарные кавычки, а дефис (в роли минуса) — на длинное тире :)

Svan 23 дн

Если хочется, чтобы «близко к стилю» SQL, то вместо `generate_series` стоит использовать рекурсивный запрос.

Евгений Степанищев 23 дн

Тоже верно, но мы всё же чаще выбираем откуда-то, generate_series тут эмулирует таблицу.

Макс 23 дн

Не вникал в твои реализации, но скажи, ведь у тебя есть несколько алгоритмов и ты смотришь какой из них лучше/легче реализовать в конкретном языке программирования? Или алгоритм один?

Евгений Степанищев 23 дн

Какой-то алгоритм за годы сложился, но иногда его приходится сильно менять, например, когда в языке нет функций или циклы организовываются как-нибудь странно (как в gnuplot, например).