SQL-запрос для поиска неоцифрованных видеозаписей на кассетах
В этой статье разберём, как написать корректный SQL-запрос, чтобы найти все видеозаписи, которые не были оцифрованы (то есть не имеют связанного файла). Исходная задача - есть база видеоархива с четырьмя таблицами: T_video (видеозаписи), T_nositel (носители: кассеты или файлы), T_type (типы носителей) и связующая таблица T_VN. Необходимо вывести только те записи, которые хранятся на кассетах, но не имеют цифровой копии (файла).
Структура базы данных видеоархива
Для понимания логики запроса важно знать схему таблиц:
- T_video - содержит информацию о видеозаписях (idVideo, nameVideo).
- T_nositel - носители (idNositel, nameNositel, typeNositel).
- T_type - типы носителей (idType, nameType). Например, id=1 - кассета, id=3 - файл.
- T_VN - связь между видео и носителями (idV, idN). Одна запись может быть на нескольких носителях.
Проблема исходного решения на VBA
Исходный код использовал функцию verifyType на VBA, которая проверяла, есть ли у видео носитель с типом 3 (файл). Если нет - запись считалась неоцифрованной. Это работало, но такой подход медленный, неудобный и привязан к Access. Гораздо лучше переписать всё на чистый SQL.
Как составить SQL-запрос для поиска неоцифрованных записей
Чтобы найти видеозаписи, у которых нет файла (typeNositel = 3), используйте оператор NOT EXISTS или LEFT JOIN с проверкой на NULL. Ниже приведён оптимальный вариант.
SQL-запрос с NOT EXISTS (рекомендуется)
SELECT v.nameVideo, n.nameNositel, t.nameType
FROM T_video v
INNER JOIN T_VN vn ON v.idVideo = vn.idV
INNER JOIN T_nositel n ON vn.idN = n.idNositel
INNER JOIN T_type t ON n.typeNositel = t.idType
WHERE NOT EXISTS (
SELECT 1
FROM T_VN vn2
INNER JOIN T_nositel n2 ON vn2.idN = n2.idNositel
WHERE vn2.idV = v.idVideo AND n2.typeNositel = 3
);Этот запрос выводит все видеозаписи вместе с их кассетами, но только те, для которых не существует ни одной записи в T_VN с типом носителя «файл» (typeNositel = 3).
SQL-запрос с LEFT JOIN и проверкой на NULL
SELECT v.nameVideo, n.nameNositel, t.nameType
FROM T_video v
INNER JOIN T_VN vn ON v.idVideo = vn.idV
INNER JOIN T_nositel n ON vn.idN = n.idNositel
INNER JOIN T_type t ON n.typeNositel = t.idType
LEFT JOIN (
SELECT DISTINCT vn2.idV
FROM T_VN vn2
INNER JOIN T_nositel n2 ON vn2.idN = n2.idNositel
WHERE n2.typeNositel = 3
) AS file_video ON v.idVideo = file_video.idV
WHERE file_video.idV IS NULL;Оба запроса дают одинаковый результат. Выбирайте тот, который легче читается в вашем проекте.
Объяснение логики
Мы присоединяем все связанные носители к видеозаписям, а затем отфильтровываем те, у которых нет связи с файлом. Если у видео есть хотя бы один файл, оно не попадает в результат. Таким образом, выводятся только записи, хранящиеся исключительно на кассетах (или других нецифровых носителях).
Что делать, если нужно вывести все записи без файлов (в том числе без носителей)
Если в базе могут быть видеозаписи, у которых вообще нет носителей (например, ещё не назначен), и вы хотите их тоже включить в выборку, замените INNER JOIN на LEFT JOIN для таблицы T_VN. Но по условию задачи, кажется, что каждая запись уже имеет хотя бы один носитель.
Заключение
Переход с VBA-функции на чистый SQL упрощает сопровождение и ускоряет выполнение запроса. Используйте NOT EXISTS или LEFT JOIN с IS NULL - оба способа корректно находят неоцифрованные видеозаписи. Теперь вы можете легко адаптировать этот запрос под свою базу данных.