7

假设我有一些 Table_A:

A_id | A_val
1      a
2      b
3      c

一些表_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

我需要帮助来尝试在表 A中找到与表 B中链接的项目最少的项目。我目前是使用 PostgreSQL 的 SQL 的初学者,并认为它可能与使用子查询有关。我设法使用以下方法计算链接:

SELECT A_id, COUNT(B_id) as Num_links
  FROM TABLE_C
  GROUP BY A_id;

但我不知道从这里去哪里。

4

6 回答 6

3

您可以使用with子句为“计数”查询提供别名,并将其视为临时表。然后选择 中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_id1 和 4 都只有 1 个链接),这可能会返回多行。

于 2013-02-06T21:16:20.020 回答
1

您可以使用RANK(). 这将为您的 Aid 排序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

这是小提琴

祝你好运。

于 2013-02-06T21:19:10.847 回答
0

这是策略。计算最大链接数。您可以通过使用order byand修改查询来做到这一点limit

接下来,计算 中每一行的链接总数tableC。为此,我使用了窗口函数。该声明:

count(*) over (partition by a_id)

说创建一个变量,它是我表中“a”的计数。

然后一起加入这个。

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
于 2013-02-06T21:12:46.053 回答
0

这是另一种选择。它在HAVING子句中使用子查询:

SELECT DISTINCT AId, COUNT(*)
FROM C
GROUP BY AId
HAVING COUNT(*) <= ALL (SELECT COUNT(*) 
                        FROM C 
                        GROUP BY AId)

和相关的小提琴。我不知道这在性能方面与其他解决方案相比如何,但它似乎清楚地表明了正在发生的事情。

于 2013-02-06T21:29:06.390 回答
0

看起来这里的其他人有一个更优雅的解决方案......我的 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;
于 2013-02-06T21:54:06.420 回答
0
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 发布的内容。它在某些方面有所不同:

  • ct在我数LEFT JOIN到的 CTE中table_c,这样我就不会错过来自0 个连接的行table_a,根据问题中的定义,这些行应该获胜。table_b
  • 使用窗口函数在 CTE 中计算min_ct(因此在最终WHERE条件中没有额外的子查询)。可能会或可能不会更快,无论如何它都更干净。
  • 最终WHERE条件良好,=而不是<=

-> sqlfiddle展示了差异。

于 2013-02-07T00:09:12.057 回答