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

SQL я впервые выучил не ради красоты — нужен был для работы. Тогда казалось: язык скучный, служебный, без «души». SELECT, WHERE, JOIN… будто молоток или отвёртка. Но однажды, копаясь в старой демо-базе, я обратил внимание на то, что данные сами по себе напоминали короткие предложения. И пришла мысль: а что, если воспринимать таблицу не как набор строк, а как страницу романа?

Сначала это выглядело как дурацкая затея, но чем дальше я шёл, тем больше SQL переставал быть «сухим инструментом» и начинал вести себя как настоящий рассказчик.

Таблицы вместо сеттинга

Любой рассказ начинается с декораций. У писателя — это сеттинг, у нас — таблица. Простейший каркас истории выглядит так:

CREATE TABLE Characters (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    role VARCHAR(50),
    mood VARCHAR(50)
);

CREATE TABLE Places (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    description TEXT
);

CREATE TABLE Events (
    id INT PRIMARY KEY,
    place_id INT,
    character_id INT,
    action TEXT,
    FOREIGN KEY (place_id) REFERENCES Places(id),
    FOREIGN KEY (character_id) REFERENCES Characters(id)
);

На этом этапе это всё ещё больше похоже на заготовку для какой-нибудь текстовой RPG, но я-то собираюсь писать «литературу».

Герои истории

Герои без базы данных не заведутся. Пусть будет программист, аналитик и ироничный ИИ.

INSERT INTO Characters (id, name, role, mood) VALUES
(1, 'Алекс', 'программист', 'усталый'),
(2, 'Ира', 'аналитик', 'вдохновлённая'),
(3, 'Бот', 'ИИ-ассистент', 'саркастичный');

Я заметил, что когда вручную вставляешь такие строки, они начинают звучать не как данные, а как заметки автора в блокноте. Почти слышишь голос персонажа.

Пространство как сцена

Чтобы что-то происходило, нужно место. Добавим его:

INSERT INTO Places (id, name, description) VALUES
(1, 'Офис', 'Открытое пространство с лампами дневного света'),
(2, 'Кафе', 'Небольшое место с запахом корицы и кофе');

Тут и началась магия: SQL внезапно стал похож на описание сцены в пьесе. Если убрать ключевые слова и скобки, получится почти готовый кусочек прозы.

Сюжетные события

Обычная литература движется событиями, у нас — INSERT INTO Events.

INSERT INTO Events (id, place_id, character_id, action) VALUES
(1, 1, 1, 'пишет SQL-запрос'),
(2, 1, 2, 'смотрит на код и улыбается'),
(3, 2, 3, 'шепчет комментарии с сарказмом');

В этот момент я впервые ощутил, что делаю нечто среднее между «базой данных для CRM» и «литературным редактором».

SELECT как рассказчик

Теперь соберём первые фразы.

SELECT c.name || ' (' || c.role || ', ' || c.mood || ')' || 
       ' находится в ' || p.name || ' и ' || e.action AS narrative
FROM Events e
JOIN Characters c ON e.character_id = c.id
JOIN Places p ON e.place_id = p.id;

Результат оказался неожиданно похож на черновик:

  • Алекс (программист, усталый) находится в Офис и пишет SQL-запрос

  • Ира (аналитик, вдохновлённая) находится в Офис и смотрит на код и улыбается

  • Бот (ИИ-ассистент, саркастичный) находится в Кафе и шепчет комментарии с сарказмом

SQL впервые заговорил «человеческим» языком.

Диалоги через UNION

Чтобы оживить историю, нужны диалоги. В SQL это делается через UNION.

SELECT c.name || ': "Хватит писать баги, пора писать истории!"' AS dialog
FROM Characters c WHERE c.id = 1
UNION
SELECT c.name || ': "Сюжет всегда живее цифр."' 
FROM Characters c WHERE c.id = 2
UNION
SELECT c.name || ': "Запишу всё это в лог, на всякий случай."' 
FROM Characters c WHERE c.id = 3;

Получилось:

  • Алекс: «Хватит писать баги, пора писать истории!»

  • Ира: «Сюжет всегда живее цифр.»

  • Бот: «Запишу всё это в лог, на всякий случай.»

Никогда раньше не думал, что UNION может работать как драматург.

Конфликт как двигатель

Литература без конфликта мертва. Сделаем генератор конфликтов:

SELECT c1.name || ' спорит с ' || c2.name || ' о ' ||
       (CASE WHEN RANDOM() % 2 = 0 THEN 'смысле данных' ELSE 'будущем технологий' END) AS conflict
FROM Characters c1
JOIN Characters c2 ON c1.id < c2.id;

Каждый запуск давал разные сцены:

  • Алекс спорит с Ирой о смысле данных

  • Алекс спорит с Бот о будущем технологий

  • Ира спорит с Бот о смысле данных

Вот она, драматургия через псевдослучайность.

Финал рассказа

Историю нужно завершить. Пусть SQL решает за нас:

SELECT name || ' понимает, что ' || 
       CASE mood
           WHEN 'усталый' THEN 'работа бесконечна'
           WHEN 'вдохновлённая' THEN 'даже данные можно превратить в искусство'
           ELSE 'машины тоже умеют иронизировать'
       END AS ending
FROM Characters;

Финал получился неожиданно философским:

  • Алекс понимает, что работа бесконечна

  • Ира понимает, что даже данные можно превратить в искусство

  • Бот понимает, что машины тоже умеют иронизировать

Бонус: интеграция с Python

Чтобы история выглядела не только как таблица, я попробовал вытянуть её в текстовую новеллу через Python:

import sqlite3

conn = sqlite3.connect(":memory:")
cursor = conn.cursor()

# Тут код создания таблиц и вставки данных такой же, как выше

for row in cursor.execute("""
SELECT c.name || ' (' || c.role || ', ' || c.mood || ')' || 
       ' в ' || p.name || ' ' || e.action AS narrative
FROM Events e
JOIN Characters c ON e.character_id = c.id
JOIN Places p ON e.place_id = p.id;
"""):
    print(row[0])

Когда выводишь это в консоль построчно, ощущение, что читаешь минималистичную новеллу. Ничего лишнего, только данные и их соединение.

Заключение

Можно ли написать рассказ на чистом SQL? Можно. И пусть это не станет бестселлером, но эксперимент показал, что язык запросов способен быть больше, чем инструментом для отчётов. SQL умеет быть и автором.

И, честно говоря, после этого опыта я стал относиться к базе данных чуть теплее. Вдруг где-то там, в её индексах, давно живёт маленький писатель?

Комментарии (1)


  1. levge
    22.08.2025 19:16

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