Зададен въпрос
Вие не можете препратка към псевдоним на таблица от една подзаявка в друга заявка на същото ниво (или в друг крак на UNION
запитване). Псевдоним на таблица се вижда само в самата заявка и нейните подзаявки.
Вие можете референтни изходни колони на подзаявка на същото ниво на заявка с LATERAL JOIN
. Пример:
Намерете най-често срещаните елементи в масива с групиране по
Решение за малък максимален брой нива
Само за няколко нива (ако знаете максимума), можете да използвате проста заявка:
LEFT JOIN
до n-1 екземпляра на самата таблица- Използвайте
COALESCE
иCASE
израз за фиксиране на корена и височината,
SELECT p1.c AS child, COALESCE(p3.p, p2.p, p1.p) AS parent
,CASE
WHEN p3.p IS NOT NULL THEN 3
WHEN p2.p IS NOT NULL THEN 2
ELSE 1
END AS height
FROM parent p1
LEFT JOIN parent p2 ON p2.c = p1.p
LEFT JOIN parent p3 ON p3.c = p2.p
WHERE p1.c IN (3, 8)
ORDER BY p1.c;
Това е стандартен SQL и трябва да работи във всички 4 RDBMS сте маркирали.
Общо решение за произволен брой нива
Използвайте рекурсивен CTE както @Ken вече посъветва.
- В рекурсивния крак запазете детето за всеки ред преместете напред само родителя.
- Във външния
SELECT
, запазете само реда с най-голямаheight
на дете.
WITH RECURSIVE cte AS (
SELECT c AS child, p AS parent, 1 AS height
FROM parent
WHERE c IN (3, 8)
UNION ALL
SELECT c.child, p.p AS parent, c.height + 1
FROM cte c
JOIN parent p ON p.c = c.parent
-- WHERE c.height < 10 -- to safeguard against endless loops if necessary
)
SELECT DISTINCT ON (child) *
FROM cte
ORDER BY child, height DESC;
DISTINCT ON
е специфичен за Postgres . Обяснение:
Изберете първия ред във всяка група GROUP BY?
Останалото ще работи по подобен начин в Oracle и дори SQLite , но не и в MySQL, който не поддържа CTE.
SQL Fiddle демонстрирайки и двете.