У меня есть две таблицы:
ИСПЫТАНИЯ:
test_prep_materials:
Поэтому к любому тесту есть подготовительные материалы. И некоторые тесты содержат тот же материал. Я хочу удалить все материалы за 2023 год и УДАЛИТЬ ФАЙЛЫ С ДИСКА. Но тесты 2024 года могут иметь тот же путь (ТОТ ЖЕ ФАЙЛ НА ДИСКЕ). Поэтому мне нужно выбрать все подготовительные материалы для тестов 2023 года и исключить из них все пути, которые имеют зависимости в тестах 2024 года.
Я попробовал следующее, но результатов слишком много, чтобы понять, правильно ли была выполнена команда.
SELECT `test_prep_materials`.`PATH`, `tests`.`id`, `tests`.`year`, `tests`.`Name_t`
from `test_prep_materials`
JOIN `tests` ON `test_prep_materials`.`tId` = `tests`.`id`
WHERE `tests`.`year` = 2023
EXCEPT
SELECT `test_prep_materials`.`PATH`, `tests`.`id`, `tests`.`year`, `tests`.`Name_t`
from `test_prep_materials`
JOIN `tests` ON `test_prep_materials`.`tId` = `tests`.`id`
WHERE `tests`.`year` <> 2023
Может ли кто-нибудь помочь мне понять, правильный ли мой запрос или я что-то упускаю?
Ваше утверждение: «Я попробовал следующее, но получено слишком много результатов, чтобы понять, правильно ли была выполнена команда». -> почему бы не использовать эту команду, чтобы проверить LIMIT 5;
, соответствуют ли результаты тому, что вы хотите.
Ваш EXCEPT вообще не будет исключать какие-либо строки, поскольку первый SELECT содержит только 2023 год, а второй SELECT содержит только другие годы. Пропустите год и посмотрите, что произойдет. (Или вместо этого используйте NOT EXISTS.)
@ThorstenKettner, да, если мы говорим только о таблице в базе данных - я могу удалить все строки для тестов 2023 года. Но я ДОЛЖЕН также удалить файлы на диске. Но проблема в том, что один и тот же файл (путь в материалах) может одновременно принадлежать как тесту 2023, так и 2024.
Чтобы найти эти пути, вам просто нужно ограничить запрос путями: SELECT m.path from test_prep_materials m JOIN tests t ON t.id = m.tId WHERE t.year = 2023 EXCEPT SELECT m.path from test_prep_materials m JOIN tests t ON t.id = m.tId WHERE t.year <> 2023
. Или суммировать: SELECT m.path from test_prep_materials m JOIN tests t ON t.id = m.tId GROUP BY m.path HAVING MIN(t.year) = 2023 AND MAX(t.year) = 2023
.
Похоже, вам нужно удалить пути из тестов прошлых лет, которые не используются ни в одном тесте этого года. Если это так, это означает, что вам нужны пути, использованные только в прошлом году и только в прошлом году - используйте Max(YEAR) = Min(YEAR) для каждого PATH и < Max(YEAR) для всех:
WITH -- S a m p l e D a t a :
tests ( ID, YEAR, DESCRIPTION ) AS
( Select 0, 2023, 'some text 0' Union All
Select 1, 2024, 'some text 1' Union All
Select 2, 2023, 'some text 2' Union All
Select 3, 2024, 'some text 3' Union All
Select 4, 2024, 'some text 4'
),
test_prep_materials ( ID, PATH, TID ) AS
( Select 100, '/home/user/file0.pdf', 0 Union All
Select 101, '/home/user/file0.pdf', 1 Union All
Select 102, '/home/user/file3.pdf', 1 Union All
Select 103, '/home/user/file3.pdf', 2 Union All
Select 104, '/home/user/file4.pdf', 3 Union All
Select 105, '/home/user/file4.pdf', 2 Union All
Select 106, '/home/user/file4.pdf', 1 Union All
Select 107, '/home/user/file5.pdf', 4 Union All
Select 108, '/home/user/file6.pdf', 0
)
-- S Q L :
Select tpm.PATH, Max(t.YEAR) as MAX_YEAR, Min(t.YEAR) as MIN_YEAR
From tests t
Left Join test_prep_materials tpm ON(tpm.TID = t.ID)
Group By tpm.PATH
HAVING Max(t.YEAR) < ( Select Max(YEAR) From tests )
/* R e s u l t :
PATH MAX_YEAR MIN_YEAR
---------------------- -------- --------
/home/user/file6.pdf 2023 2023 */
ИЛИ со всеми данными из таблицы тестов:
-- S Q L :
SELECT t.*, tpm.PATH
FROM tests t
INNER JOIN ( Select tpm.PATH, Max(t.YEAR) as MAX_YEAR, Min(t.YEAR) as MIN_YEAR
From tests t
Left Join test_prep_materials tpm ON(tpm.TID = t.ID)
Group By tpm.PATH
HAVING Max(t.YEAR) < ( Select Max(YEAR) From tests )
) tpm ON( t.YEAR Between tpm.MIN_YEAR And tpm.MAX_YEAR )
Where t.YEAR < ( Select Max(YEAR) From tests )
/* R e s u l t :
ID YEAR DESCRIPTION PATH
-- ---- ----------- ------------------------
0 2023 some text 0 /home/user/file6.pdf
2 2023 some text 2 /home/user/file6.pd */
ПРИМЕЧАНИЕ:
Если вы хотите сослаться на какой-либо конкретный год в диапазоне (например, с 2021 по 2026 год), измените подзапрос, выбрав Max(YEAR) для всего конкретного года, скажем, 2025 года, и результатом должны быть пути, использованные до 2025 года, а не в 2025 году. Однако этого не было в ваших выборочных данных.
...
HAVING Max(t.YEAR) < 2025
...
Это можно еще больше настроить с помощью различных условий предложения Where.
ЕЩЕ ОДИН ПОДХОД:
Если у вас есть период в годах, например, с 2021 по 2026 год, и вы хотите обратиться к 2024 году в поисках предыдущих путей, отсутствующих в 2024 году, вы можете сделать что-то вроде ниже, но с жестко запрограммированным базовым годом (2024):
WITH -- S a m p l e D a t a :
tests ( ID, YEAR, DESCRIPTION ) AS
( Select 0, 2023, 'some text 0' Union All
Select 1, 2024, 'some text 1' Union All
Select 2, 2023, 'some text 2' Union All
Select 3, 2024, 'some text 3' Union All
Select 4, 2024, 'some text 4' Union All
-- new rows below
Select 5, 2021, 'some text 5' Union All
Select 6, 2024, 'some text 6' Union All
Select 7, 2026, 'some text 7'
),
test_prep_materials ( ID, PATH, TID ) AS
( Select 100, '/home/user/file0.pdf', 0 Union All
Select 101, '/home/user/file0.pdf', 1 Union All
Select 102, '/home/user/file3.pdf', 1 Union All
Select 103, '/home/user/file3.pdf', 2 Union All
Select 104, '/home/user/file4.pdf', 3 Union All
Select 105, '/home/user/file4.pdf', 2 Union All
Select 106, '/home/user/file4.pdf', 1 Union All
Select 107, '/home/user/file5.pdf', 4 Union All
Select 108, '/home/user/file6.pdf', 0 Union All
-- new rows below
Select 108, '/home/user/file6.pdf', 5 Union All
Select 108, '/home/user/file5.pdf', 6 Union All
Select 108, '/home/user/file5.pdf', 7
)
-- S Q L :
Select tpm.PATH, Max(t.YEAR) as MAX_YEAR, Min(t.YEAR) as MIN_YEAR
From tests t
Left Join test_prep_materials tpm ON(tpm.TID = t.ID)
Group By tpm.PATH
HAVING Count((Select 1 From tests Where ID = t.ID And Year = 2024)) = 0 And
Max(Case When t.YEAR <= 2024 Then t.YEAR Else 9999 End ) < 2024
/* R e s u l t :
PATH MAX_YEAR MIN_YEAR
---------------------- -------- --------
/home/user/file6.pdf 2023 2021 */
Можете ли вы помочь мне понять ваш первый SQL-скрипт? как его отредактировать в таком случае, что я могу выбрать, материалы какого именно года я удаляю? например в какой-то момент у меня может быть 2023-2026 год. Итак, если я правильно понимаю Query, он вернет все материалы только за 2023 год, только за 2024 год, только за 2025 год. А я например хочу удалить только за 2025 год
@ASDORDSAUSER Только что обновил ответ с помощью ---> HAVING Max(t.YEAR) < (Выберите Max(YEAR) Из тестов)
Я думаю, что что-то не так со вторым запросом. Данные испытаний: 1 - Тест1 - 2023 2 - Тест2 - 2024 3 - Тест3 - 2023 4 - Тест4 - 2024 ---- 1 - /a/b - 1 2 - /a/b - 2 3 - /c/d - 3 4 - /e/f - 4 Так что я ожидаю увидеть только Test3 - 2023 - /c/d Получил: Test1 - 2023 - /c/d Test3 - 2023 - /c/d
@ASDORDSAUSER Это тоже исправлено. Изменено предложение ON и добавлено предложение WHERE. Это необходимо на протяжении нескольких последних лет.
@ASDORDSAUSER Посмотрите скрипку за несколько прошлых лет --> dbfiddle.uk/4iMQrFg1
idk второй запрос, похоже, работает неправильно, но все равно возвращает 2 значения. dbfiddle.uk/Yj569teC
@ASDORDSAUSER Как и предполагалось и как указано в ответе «ИЛИ со всеми данными из таблицы тестов:» - он показывает строки из таблицы тестов, связанные с рассматриваемыми ПУТЯМИ «/home/user/file6.pdf "...
ааа! Попался. Вам большое за помощь! Ты спас меня!
@ASDORDSAUSER Добавлен еще один подход на случай, если у вас есть данные за прошлые и будущие годы...
Вы можете использовать следующий запрос, он устранит общий путь для обоих лет и предоставит вам путь, который вы можете удалить.
select *from test_prep_materials tpm inner join tests t
on t.id = tpm.tid
where t.year = '2023'
and exists (select path from test_prep_materials tpm2 inner join tests t
on t.id=tpm.id and t.year = 2024 -- t.year != 2023
where tpm2.path =tpm.path
)
Что-то здесь не так. Вы говорите, что хотите удалить материалы, которые актуальны только для испытаний 2023 года и никаких других лет. Я ожидал найти идентификатор материала в таблице тестов, но вместо этого в таблице материалов оказался идентификатор теста. Таким образом, каждая запись материала относится ровно к одному испытанию, а именно к тому, которое указано в tid. В вашей модели данных не может быть записи материала, которая используется более чем в одном тесте. Есть ли что-то, чего я не вижу?