SQL: как найти минимальное количество записей, связанных из одной таблицы в другую
допустим, у меня есть Table_A:
A_id | A_val
1 a
2 b
3 c
Некоторые Table_B:
B_id | B_val
1 d
2 e
3 g
и компоновщик Table_C:
A_id | B_id
1 1
2 1
2 2
3 1
3 2
3 3
мне нужна помощь, чтобы найти элементы!--11-->Таблица A, который имеет наименьшее количество элементов в Таблица B связаны с ним. В настоящее время я новичок в SQL с использованием PostgreSQL и решил, что это может иметь какое-то отношение к использованию подзапроса. Мне удалось подсчитать ссылки, используя:
SELECT A_id, COUNT(B_id) as Num_links
FROM TABLE_C
GROUP BY A_id;
но Я понятия не имею, куда идти дальше.
6 ответов
вы могли бы использовать with
предложение, чтобы дать псевдоним вашему запросу "count" и рассматривать его как временную таблицу. Выберите a_id
С num_links
меньше-чем-или-равно-до самого низкого рассчитывать в num_links
.
WITH link_counts AS (
SELECT a_id, COUNT(b_id) as num_links
FROM table_c
GROUP BY a_id
)
SELECT a_id
FROM link_counts
WHERE num_links <= (SELECT MIN(num_links) FROM link_counts)
обратите внимание, что это может вернуть несколько строк, если разные a_id
имеют одинаковое (наименьшее) количество ссылок (например, если a_id
1 и 4 оба имели только по 1 ссылке).
можно использовать RANK()
. Это будет ранжировать вашу помощь по COUNT(Bid)
-- для тех, у кого одинаковое число, все будут возвращены с одинаковым рангом.
SELECT *
FROM A T1
JOIN (
SELECT Aid, RANK() OVER (ORDER BY COUNT(Bid)) rnk
FROM C
GROUP BY Aid
) T2 ON T1.Id = T2.Aid
WHERE T2.rnk = 1
и вот это Скрипка.
удачи.
вот еще один вариант. Он использует подзапрос в HAVING
статья:
SELECT DISTINCT AId, COUNT(*)
FROM C
GROUP BY AId
HAVING COUNT(*) <= ALL (SELECT COUNT(*)
FROM C
GROUP BY AId)
и связанные с скрипка. Я понятия не имею, как это будет сравниваться с другими решениями с точки зрения производительности, но, похоже, это ясно показывает, что происходит.
вот стратегия. Рассчитайте максимальное количество ссылок. Вы можете сделать это, изменив свой запрос с помощью order by
и limit
.
Далее следует рассчитать общее количество ссылок для каждой строки tableC
. Для этого я использую функцию window. Заявление:
count(*) over (partition by a_id)
говорит создать переменную, которая является количеством " a " s в моей таблице.
тогда соедините это вместе.
select distinct c.a_id
from (select c.*,
count(*) over (partition by a_id) as num_links
from table_c c
) c join
(select a_id, count(*) as num_links
from table_c c
group by a_id
order by 2 asc
limit 1
) cmax
on c.num_links = cmax.num_links
WITH ct AS (
SELECT a.a_id
,count(c.a_id) AS link_ct
,min(count(c.a_id)) OVER () AS min_ct
FROM table_a a
LEFT JOIN table_c c USING (a_id)
GROUP BY 1
)
SELECT a_id, link_ct
FROM ct
WHERE link_ct = min_ct;
это похоже на то, что @ matts posted. Он отличается в некоторых аспектах:
- в CTE
ct
Я считаюLEFT JOIN
totable_c
, таким образом я не пропускаю строкиtable_a
С 0 соединения totable_b
который должен выиграть в соответствии с определением в вопросе. - вычислить
min_ct
в CTE с оконной функцией (и, следовательно, без дополнительного подзапроса в finalWHERE
состояние). Может или не может быстрее, в любом случае чище. - финал
WHERE
состояние хорошее с=
вместо<=
.
->sqlfiddle демонстрируя разницу.
похоже, что у других здесь есть более элегантное решение... мой SQL Fu немного ржавый, но это тоже сработает.
CREATE TABLE Table_C
(
A_id INT,
B_id INT
);
INSERT INTO Table_C (A_id, B_id) VALUES (13, 112);
INSERT INTO Table_C (A_id, B_id) VALUES (44, 105);
INSERT INTO Table_C (A_id, B_id) VALUES (66, 68);
INSERT INTO Table_C (A_id, B_id) VALUES (13, 113);
INSERT INTO Table_C (A_id, B_id) VALUES (445, 105);
INSERT INTO Table_C (A_id, B_id) VALUES (660, 68);
CREATE TABLE TempTable
(
A_id INT,
Cnt INT
);
INSERT INTO
TempTable (A_id, Cnt)
SELECT
t.A_id
, COUNT(t.A_id) AS Cnt
FROM
Table_C t
GROUP BY
t.A_id;
SELECT @minCnt := MIN(Cnt) FROM TempTable;
SELECT
A_id
FROM
Table_C
GROUP BY
A_id
HAVING
COUNT(A_id) = @minCnt;