Дана таблица в которой перечислены все дуги связного ориентированного графа. В таблице два числовых поля, в первом указана начальная вершина дуги, во втором – конечная вершина.
Требуется:
Написать SQL запрос, который возвращает список дуг, при добавлении которых граф станет полным.
Для начала код для тестовой таблицы (Postgresql):
CREATE TEMPORARY TABLE graph
(
start_point INTEGER NOT NULL,
end_point INTEGER NOT NULL
)
ON COMMIT DROP;
INSERT INTO graph VALUES
(1,2),
(1,4),
(2,3),
(3,4);
И собственно, мой вариант решения:
-- Для начала нужно получить список всех-всех дуг для данного графа
WITH a AS (
WITH points AS(
-- Получаем все вершины, преобразовывем в массив
SELECT array(SELECT DISTINCT start_point FROM graph ORDER BY start_point) ||
array(SELECT DISTINCT end_point FROM graph ORDER BY end_point)
AS allp FROM student
LIMIT 1
)
SELECT DISTINCT i
FROM unnest ((SELECT * FROM points)) AS s(i)
),
all_possible_edges AS(
SELECT *
FROM
-- И затем все эти вершины комбинируем друг с другом
a CROSS JOIN a AS b
WHERE
-- Это условие означает, что пропускаем 1-1. Также оно означает, что будет только дуга 1-2, но не 2-1
-- Хотя эти дуги одинаковы по смыслу
a < b
ORDER BY a, b
)
-- Ну и наконец берем только те дуги, которые есть в комбинациях, но которых нет в оригинальной таблице
SELECT * FROM all_possible_edges EXCEPT SELECT * FROM graph
Ответ:
>> 2;4
>> 1;3
Проблема в том, что меня не покидает чувство, что решение переусложнено. Особенно омерзительно выглядит возня с массивами. Есть ли способы решить задачу проще?
Для postgersql
WITH ps AS (
SELECT /* DISTINCT */ start_point AS point FROM graph
UNION /* DISTINCT */
SELECT /* DISTINCT */ end_point FROM graph
),
pe AS (
SELECT /* DISTINCT */ start_point AS point FROM graph
UNION /* DISTINCT */
SELECT /* DISTINCT */ end_point FROM graph
)
SELECT ps.point start_point, pe.point end_point
FROM ps, pe
WHERE ps.point != pe.point
EXCEPT
SELECT start_point, end_point
FROM graph;
http://www.sqlfiddle.com/#!15/6ef70/3/0
Для MySQL
SELECT ps.point start_point, pe.point end_point
FROM (
SELECT /* DISTINCT */ start_point AS point FROM graph
UNION /* DISTINCT */
SELECT /* DISTINCT */ end_point FROM graph
) ps, (
SELECT /* DISTINCT */ start_point AS point FROM graph
UNION /* DISTINCT */
SELECT /* DISTINCT */ end_point FROM graph
) pe
WHERE ps.point != pe.point
AND (ps.point, pe.point) NOT IN
(SELECT start_point, end_point
FROM graph);
http://www.sqlfiddle.com/#!9/6ef708/4/0
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Вот, к примеру, есть всего 10 достаточно больших блоков с каким-либо фоном, которые не умещаются на экранеВ строке по 2 таких блока
Здравствуйте! Стал интересен парсинг html-страниц, начал разбираться с Jsoup, почитал несколько довольно стареньких гайдов по этому поводу(там...
При передаче объекта в качестве параметра методу ссылка должна копироватьсяТогда почему вывод 0 9 9, а не 9 9 9? Получается, s1 и s2 ссылаются на разные...