Files
DanceVideos/model/videos_summary.sql
2025-10-16 17:18:58 +02:00

244 lines
8.7 KiB
SQL
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- ============================================================================
-- VIEW : playlist_videos
-- ============================================================================
DROP VIEW IF EXISTS playlist_videos;
CREATE VIEW playlist_videos AS
WITH
-- 1⃣ Playlists manuelles
manual_playlists_videos AS (
SELECT
p.id AS playlist_id,
p.name AS playlist_name,
'manual' AS playlist_type,
vp.video_file_name
FROM playlists p
JOIN video_playlists vp ON p.id = vp.playlist_id
WHERE p.type = 'manual'
),
-- 2⃣ Dynamiques sans include/exclude
dynamic_playlist_videos_base AS (
SELECT DISTINCT
p.id AS playlist_id,
p.name AS playlist_name,
'dynamic' AS playlist_type,
v.file_name AS video_file_name
FROM playlists p
JOIN videos v
WHERE p.type = 'dynamic'
-- Labels inclus (AND/OR)
AND (
json_array_length(json_extract(p.rules_json, '$.include_labels')) = 0
OR (
json_extract(p.rules_json, '$.label_logic') = 'OR'
AND EXISTS (
SELECT 1 FROM json_each(json_extract(p.rules_json, '$.include_labels')) jl
JOIN labels l ON l.name = jl.value
JOIN video_labels vl ON vl.label_id = l.id AND vl.video_file_name = v.file_name
)
)
OR (
json_extract(p.rules_json, '$.label_logic') = 'AND'
AND NOT EXISTS (
SELECT 1
FROM json_each(json_extract(p.rules_json, '$.include_labels')) jl
WHERE jl.value NOT IN (
SELECT l2.name
FROM labels l2
JOIN video_labels vl2 ON l2.id = vl2.label_id
WHERE vl2.video_file_name = v.file_name
)
)
)
)
-- Labels exclus
AND NOT EXISTS (
SELECT 1 FROM json_each(json_extract(p.rules_json, '$.exclude_labels')) je
JOIN labels lx ON lx.name = je.value
JOIN video_labels vlx ON vlx.label_id = lx.id AND vlx.video_file_name = v.file_name
)
-- Dates
AND (
json_extract(p.rules_json, '$.date_after') IS NULL
OR v.record_datetime >= json_extract(p.rules_json, '$.date_after')
OR (
json_extract(p.rules_json, '$.date_delta_days') IS NOT NULL
AND v.record_datetime >= date('now', (json_extract(p.rules_json, '$.date_delta_days') || ' days'))
)
)
AND (
json_extract(p.rules_json, '$.date_before') IS NULL
OR v.record_datetime <= json_extract(p.rules_json, '$.date_before')
)
-- Difficulty / day / address
AND (
json_extract(p.rules_json, '$.difficulty') IS NULL
OR v.difficulty_level = json_extract(p.rules_json, '$.difficulty')
)
AND (
json_extract(p.rules_json, '$.day_of_week') IS NULL
OR v.day_of_week = json_extract(p.rules_json, '$.day_of_week')
)
AND (
json_extract(p.rules_json, '$.address_keyword') IS NULL
OR (
v.address NOT LIKE '%unknown%'
AND v.address LIKE '%' || json_extract(p.rules_json, '$.address_keyword') || '%'
)
)
),
-- 3⃣ Inclusions directes (parent → enfant)
playlist_direct_includes AS (
SELECT
p.id AS parent_playlist_id,
CAST(inc.value AS INTEGER) AS child_playlist_id
FROM playlists p
JOIN json_each(json_extract(p.rules_json, '$.include_playlists')) inc
ON json_type(inc.value) IN ('integer', 'text')
WHERE json_array_length(json_extract(p.rules_json, '$.include_playlists')) > 0
),
-- 4⃣ Récursion : parent → descendant (transitif)
playlist_includes_recursive AS (
WITH RECURSIVE rec(parent_playlist_id, child_playlist_id) AS (
SELECT parent_playlist_id, child_playlist_id FROM playlist_direct_includes
UNION ALL
SELECT d.parent_playlist_id, di.child_playlist_id
FROM playlist_direct_includes d
JOIN rec di ON di.parent_playlist_id = d.child_playlist_id
)
SELECT DISTINCT parent_playlist_id AS parent_id, child_playlist_id AS child_id FROM rec
),
-- 5⃣ Exclusions directes et récursives
playlist_direct_excludes AS (
SELECT
p.id AS parent_playlist_id,
CAST(exc.value AS INTEGER) AS child_playlist_id
FROM playlists p
JOIN json_each(json_extract(p.rules_json, '$.exclude_playlists')) exc
ON json_type(exc.value) IN ('integer', 'text')
WHERE json_array_length(json_extract(p.rules_json, '$.exclude_playlists')) > 0
),
playlist_excludes_recursive AS (
WITH RECURSIVE rec_ex(parent_playlist_id, child_playlist_id) AS (
SELECT parent_playlist_id, child_playlist_id FROM playlist_direct_excludes
UNION ALL
SELECT d.parent_playlist_id, di.child_playlist_id
FROM playlist_direct_excludes d
JOIN rec_ex di ON di.parent_playlist_id = d.child_playlist_id
)
SELECT DISTINCT parent_playlist_id AS parent_id, child_playlist_id AS child_id FROM rec_ex
),
-- 6⃣ Vidéos issues des playlists incluses
playlist_included_videos AS (
SELECT pir.parent_id AS parent_playlist_id, mpv.video_file_name
FROM playlist_includes_recursive pir
JOIN manual_playlists_videos mpv ON mpv.playlist_id = pir.child_id
UNION
SELECT pir.parent_id AS parent_playlist_id, dpb.video_file_name
FROM playlist_includes_recursive pir
JOIN dynamic_playlist_videos_base dpb ON dpb.playlist_id = pir.child_id
),
-- 7⃣ Inclusion logique OR
playlist_includes_union AS (
SELECT DISTINCT db.playlist_id, db.playlist_name, db.playlist_type, db.video_file_name
FROM dynamic_playlist_videos_base db
JOIN playlists p ON p.id = db.playlist_id
WHERE json_extract(p.rules_json, '$.logic') = 'OR'
UNION
SELECT DISTINCT iv.parent_playlist_id AS playlist_id,
(SELECT name FROM playlists WHERE id = iv.parent_playlist_id) AS playlist_name,
'dynamic' AS playlist_type,
iv.video_file_name
FROM playlist_included_videos iv
JOIN playlists p ON p.id = iv.parent_playlist_id
WHERE json_extract(p.rules_json, '$.logic') = 'OR'
),
-- 8⃣ Inclusion logique AND (+ fallback si 0 include)
playlist_includes_intersection AS (
SELECT DISTINCT db.playlist_id, db.playlist_name, db.playlist_type, db.video_file_name
FROM dynamic_playlist_videos_base db
JOIN playlists p ON p.id = db.playlist_id
WHERE json_extract(p.rules_json, '$.logic') = 'AND'
AND json_array_length(json_extract(p.rules_json, '$.include_playlists')) > 0
AND db.video_file_name IN (
SELECT iv.video_file_name
FROM playlist_included_videos iv
WHERE iv.parent_playlist_id = db.playlist_id
)
UNION ALL
SELECT DISTINCT db.playlist_id, db.playlist_name, db.playlist_type, db.video_file_name
FROM dynamic_playlist_videos_base db
JOIN playlists p ON p.id = db.playlist_id
WHERE json_extract(p.rules_json, '$.logic') = 'AND'
AND (
json_array_length(json_extract(p.rules_json, '$.include_playlists')) IS NULL
OR json_array_length(json_extract(p.rules_json, '$.include_playlists')) = 0
)
),
-- 9⃣ Fusion des deux logiques dinclusion
playlist_after_includes AS (
SELECT * FROM playlist_includes_union
UNION ALL
SELECT * FROM playlist_includes_intersection
),
-- 🔟 Vidéos exclues (via exclude_playlists récursif)
playlist_excluded_videos AS (
SELECT per.parent_id AS parent_playlist_id, mpv.video_file_name
FROM playlist_excludes_recursive per
JOIN manual_playlists_videos mpv ON mpv.playlist_id = per.child_id
UNION
SELECT per.parent_id AS parent_playlist_id, dpb.video_file_name
FROM playlist_excludes_recursive per
JOIN dynamic_playlist_videos_base dpb ON dpb.playlist_id = per.child_id
),
-- 1⃣1⃣ Application des exclusions
playlist_after_excludes AS (
SELECT pai.playlist_id, pai.playlist_name, pai.playlist_type, pai.video_file_name
FROM playlist_after_includes pai
LEFT JOIN playlist_excluded_videos pev
ON pev.parent_playlist_id = pai.playlist_id AND pev.video_file_name = pai.video_file_name
WHERE pev.parent_playlist_id IS NULL
)
-- 1⃣2⃣ Résultat final : union manuelles + dynamiques
SELECT playlist_id, playlist_name, playlist_type, video_file_name
FROM manual_playlists_videos
UNION ALL
SELECT playlist_id, playlist_name, playlist_type, video_file_name
FROM playlist_after_excludes;
-- ============================================================================
-- TABLE AGRÉGÉE : video_summary
-- ============================================================================
DROP VIEW IF EXISTS video_summary;
CREATE VIEW video_summary AS
SELECT
v.file_name,
v.raw_file,
v.mp4_file,
v.record_datetime,
v.day_of_week,
v.difficulty_level,
v.address,
GROUP_CONCAT(DISTINCT l.name) AS labels,
GROUP_CONCAT(DISTINCT pv.playlist_name) AS playlists
FROM videos v
LEFT JOIN video_labels vl ON vl.video_file_name = v.file_name
LEFT JOIN labels l ON l.id = vl.label_id
LEFT JOIN playlist_videos pv ON pv.video_file_name = v.file_name
GROUP BY v.file_name;
CREATE TABLE IF NOT EXISTS video_summary_materialized AS
SELECT * FROM video_summary;