7

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

テーブル Bにリンクされているアイテムが最も少ないテーブル Aのアイテムを見つけようとする助けが必要です。私は現在、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_linksnum_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()。これにより、あなたのエイドがランク付けされます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

そして、ここにFiddleがあります。

幸運を。

于 2013-02-06T21:19:10.847 に答える
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私が数えるCTEでは、このようにLEFT JOINして、質問の定義に従って勝つはずの接続が0table_cの行を見逃すことはありません。table_atable_b
  • min_ctウィンドウ関数を使用して(したがって、最終WHERE条件で追加のサブクエリを使用せずに) CTEで計算します。高速である場合とそうでない場合がありますが、いずれの場合もクリーンです。
  • の代わりに最終WHERE状態は良好です。=<=

->sqlfiddleが違いを示しています。

于 2013-02-07T00:09:12.057 に答える
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

これが戦略です。リンクの最大数を計算します。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)

そして関連するfiddle。これがパフォーマンスの点で他のソリューションとどのように比較されるかはわかりませんが、何が起こっているかを明確に示しているようです.

于 2013-02-06T21:29:06.390 に答える