Двойной NOT EXISTS: реляционное деление без подсчёта строк!
Задачи вида «найти сущности, удовлетворяющие всем условиям из некоторого набора» встречаются регулярно: все разрешения роли, все обязательные атрибуты товара, все зависимости конфигурации или все компетенции проекта. В реляционной алгебре такой класс задач связан с операцией деления.
Предположим, требования проекта и навыки сотрудников представлены отношениями:
Требуется получить сотрудников, обладающих всеми навыками проекта
Запрос корректен, если
Но условие «сотрудник имеет все требуемые навыки» можно выразить напрямую: не должно существовать требования, для которого у сотрудника нет соответствующего навыка:
Внешний
Если проект требует навыки
На практике такие дубли лучше запрещать ограничениями:
Также
Если у проекта
Двойной
🔥 Для условий вида «выполнены все требования», «присутствуют все зависимости» или «есть соответствие каждому элементу набора» это одна из наиболее естественных форм реляционного деления в SQL.
➡️ SQL Ready | #практика
Задачи вида «найти сущности, удовлетворяющие всем условиям из некоторого набора» встречаются регулярно: все разрешения роли, все обязательные атрибуты товара, все зависимости конфигурации или все компетенции проекта. В реляционной алгебре такой класс задач связан с операцией деления.
Предположим, требования проекта и навыки сотрудников представлены отношениями:
project_requirements(project_id, skill_id)
employee_skills(employee_id, skill_id)
Требуется получить сотрудников, обладающих всеми навыками проекта
42. Один из распространённых вариантов — подсчитать совпадения:SELECT e.id
FROM employees e
JOIN employee_skills s
ON s.employee_id = e.id
JOIN project_requirements r
ON r.project_id = 42
AND r.skill_id = s.skill_id
GROUP BY e.id
HAVING COUNT(DISTINCT r.skill_id) = (
SELECT COUNT(DISTINCT skill_id)
FROM project_requirements
WHERE project_id = 42
);
Запрос корректен, если
skill_id не допускает NULL. DISTINCT необходим, если уникальность пар (project_id, skill_id) и (employee_id, skill_id) не гарантирована схемой.Но условие «сотрудник имеет все требуемые навыки» можно выразить напрямую: не должно существовать требования, для которого у сотрудника нет соответствующего навыка:
SELECT e.id
FROM employees e
WHERE NOT EXISTS (
SELECT 1
FROM project_requirements r
WHERE r.project_id = 42
AND NOT EXISTS (
SELECT 1
FROM employee_skills s
WHERE s.employee_id = e.id
AND s.skill_id = r.skill_id
)
);
Внешний
NOT EXISTS ищет отсутствие невыполненных требований, а внутренний проверяет отсутствие соответствующего навыка. Важное свойство — дубли не влияют на результат:INSERT INTO employee_skills (employee_id, skill_id)
VALUES
(7, 10),
(7, 10),
(7, 20);
Если проект требует навыки
10 и 20, сотрудник 7 удовлетворяет требованиям независимо от числа повторений (7, 10). EXISTS проверяет наличие строки, а не их количество.На практике такие дубли лучше запрещать ограничениями:
ALTER TABLE project_requirements
ADD CONSTRAINT uq_project_requirement
UNIQUE (project_id, skill_id);
ALTER TABLE employee_skills
ADD CONSTRAINT uq_employee_skill
UNIQUE (employee_id, skill_id);
Также
skill_id в такой модели обычно следует объявлять NOT NULL. Иначе COUNT(DISTINCT skill_id) игнорирует NULL, а сравнение s.skill_id = r.skill_id с NULL не даст совпадения, что может привести к различию результатов двух подходов.Если у проекта
42 вообще нет требований, двойной NOT EXISTS вернёт всех сотрудников: нет ни одного требования, которое сотрудник не выполняет. Если по правилам предметной области проект без требований не должен возвращать кандидатов, это нужно указать отдельно:SELECT e.id
FROM employees e
WHERE EXISTS (
SELECT 1
FROM project_requirements r
WHERE r.project_id = 42
)
AND NOT EXISTS (
SELECT 1
FROM project_requirements r
WHERE r.project_id = 42
AND NOT EXISTS (
SELECT 1
FROM employee_skills s
WHERE s.employee_id = e.id
AND s.skill_id = r.skill_id
)
);
Двойной
NOT EXISTS полезен тем, что выражает исходную задачу напрямую: вместо подсчёта совпадений мы проверяем отсутствие хотя бы одного невыполненного требования.Please open Telegram to view this post
VIEW IN TELEGRAM
👍16❤7🔥6
Объединение значений с CONCAT и CONCAT_WS, агрегация строк с STRING_AGG, извлечение отдельных частей с SPLIT_PART, преобразование строк в массивы и обратно с STRING_TO_ARRAY и ARRAY_TO_STRING, а также разделение данных по регулярным выражениям с REGEXP_SPLIT_TO_ARRAY и REGEXP_SPLIT_TO_TABLE. Полезно для обработки списков, тегов, адресов и других текстовых данных.Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤17👍8🔥5
В этой статье:
• Узнаете, зачем крупным системам переходить от одной базы к распределённому хранению данных;• Разберётесь, как работает выбор шарда и какие архитектурные решения помогают масштабировать PostgreSQL;• Посмотрите на инженерные подходы из высоконагруженного продакшена.🔊 Продолжай читать на Habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10👍7🔥5
Например,
ROUND() используется для округления значений, MOD() — для получения остатка от деления, а агрегатные функции AVG(), SUM(), MIN() и MAX() помогают выполнять вычисления по наборам данных.На изображении собраны основные числовые функции: назначение, синтаксис, примеры запросов и особенности использования в разных СУБД.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤13🔥8🤝3👍2
This media is not supported in your browser
VIEW IN TELEGRAM
В репозитории собраны материалы для изучения работы с базами данных: от основ SQL и проектирования таблиц до функций, индексов, транзакций, оконных функций, PL/pgSQL и продвинутых возможностей PostgreSQL. Отличный вариант, чтобы разобраться с базами данных и перейти от простых запросов к пониманию работы СУБД.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17❤6🔥4🤝1
This media is not supported in your browser
VIEW IN TELEGRAM
Онлайн-учебник для изучения SQL: от базовых запросов до более сложной работы с данными. Теория сопровождается примерами и упражнениями, поэтому изученные конструкции можно сразу закреплять на практике. Материал разделён на главы, что удобно для поэтапного обучения.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤16👍7🤝3🔥2
🔎 Гибридный поиск в YDB: когда SQL ищет не только по словам
В YDB, созданном Yandex B2B Tech, появился гибридный поиск, который объединяет полнотекстовый и векторный поиск.
Полнотекстовый поиск находит точные совпадения, а векторный — данные, близкие по смыслу. Вместе они позволяют, например, найти документ по номеру и одновременно учесть описание нужной ситуации.
Главное — для этого больше не обязательно собирать отдельный стек из БД, поискового движка и векторного хранилища. В YDB оба индекса работают как распределённые таблицы и обновляются в одной транзакции с основными данными.
Подход можно использовать для поиска по документам, базам знаний, каталогам, тикетам и в RAG-системах. Поиск доступен в enterprise-редакции версии 26.3 для использования в on-premises и в Managed Service for YDB.
15 октября на митапе эксперты YDB объяснят, как реализовать гибридный поиск в рамках одной СУБД и повысить качество работы ИИ-агентов и рекомендательных систем.
👉 Регистрация
В YDB, созданном Yandex B2B Tech, появился гибридный поиск, который объединяет полнотекстовый и векторный поиск.
Полнотекстовый поиск находит точные совпадения, а векторный — данные, близкие по смыслу. Вместе они позволяют, например, найти документ по номеру и одновременно учесть описание нужной ситуации.
Главное — для этого больше не обязательно собирать отдельный стек из БД, поискового движка и векторного хранилища. В YDB оба индекса работают как распределённые таблицы и обновляются в одной транзакции с основными данными.
Подход можно использовать для поиска по документам, базам знаний, каталогам, тикетам и в RAG-системах. Поиск доступен в enterprise-редакции версии 26.3 для использования в on-premises и в Managed Service for YDB.
15 октября на митапе эксперты YDB объяснят, как реализовать гибридный поиск в рамках одной СУБД и повысить качество работы ИИ-агентов и рекомендательных систем.
👉 Регистрация
❤2👎1🔥1🤝1
Настройте оценку пользовательских функций!
Для пользовательской функции PostgreSQL позволяет явно указать стоимость вызова через
Причём пересоздавать функцию не обязательно:
Чем выше
PostgreSQL прямо предоставляет
🔥 Если пользовательская функция ломает оценки строк или вызывается слишком часто, проверьте
➡️ SQL Ready | #совет
Для пользовательской функции PostgreSQL позволяет явно указать стоимость вызова через
COST, а для функции, возвращающей набор строк, — ожидаемое число строк через ROWS. Причём пересоздавать функцию не обязательно:
ALTER FUNCTION find_orders(bigint)
ROWS 5;
ALTER FUNCTION expensive_check(jsonb)
COST 500;
Чем выше
COST, тем дороже планировщик считает вычисление и тем сильнее старается не выполнять его лишний раз. PostgreSQL прямо предоставляет
COST и ROWS как информацию для оптимизации пользовательских функций. EXPLAIN (ANALYZE, BUFFERS)
SELECT u.id, o.*
FROM users u
CROSS JOIN LATERAL find_orders(u.id) o;
COST и ROWS — иногда правильный план получается без переписывания запроса и новых индексов.Please open Telegram to view this post
VIEW IN TELEGRAM
❤11👍8🔥4
Проверяйте JSON без преобразования!
Если JSON приходит как
Можно сразу потребовать конкретный тип
Есть и более интересная проверка — запрет повторяющихся ключей:
Это можно использовать непосредственно в ограничении таблицы:
🔥
➡️ SQL Ready | #совет
Если JSON приходит как
text, необязательно делать ::jsonb и ловить ошибку преобразования. IS JSON просто вернёт true или false.SELECT '{"id": 42}' IS JSON; -- true
SELECT '{broken}' IS JSON; -- falseМожно сразу потребовать конкретный тип
JSON:SELECT payload IS JSON OBJECT
FROM staging;
SELECT payload IS JSON ARRAY
FROM staging;
Есть и более интересная проверка — запрет повторяющихся ключей:
SELECT '{"id":1,"id":2}'
IS JSON OBJECT WITH UNIQUE KEYS;
-- falseЭто можно использовать непосредственно в ограничении таблицы:
CREATE TABLE incoming_events (
payload text NOT NULL
CHECK (payload IS JSON OBJECT WITH UNIQUE KEYS)
);
IS JSON позволяет валидировать JSON как обычное условие SQL — без преобразований, исключений и регулярных выражений.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍5🤝3❤1