質問

私は2つの列を持つテーブルを持っています、FirstNameとLastNameとしましょう。最初のテーブルからのFirstNameのすべてのペアに共通のLastNameの数が含まれている別のテーブルを取得する必要があります。

これはSQLで行うことも可能ですか?

これがクエリの効率に影響を与える場合、FirstNameよりもはるかに多くの一意のLastNameがあります。

おもちゃの例、入力:

FirstName, LastName
John, Smith
John, Doe
Jane, Doe

出力:

FirstName1, FirstName2, CommonLastNames
John, John, 2
John, Jane, 1
Jane, Jane, 1
Jane, John, 1

この関係は反射的で対称的であるため、結果が三角形の1つ(たとえば、対角線の上のもの)であれば問題ありません。

役に立ちましたか?

解決

手にコピーを持っているので、MS SQL Serverを実行するつもりです。私はほとんどの専攻が同様にそれをするだろうと私は信じています。

サンプルテーブルとデータ付きサンプルテーブル。テーブル変数を使用しますが、テーブルのフレーバーについても同じです。

declare @t table (FirstName char(10), LastName char(10));

insert @t(FirstName,LastName)
values ('John','Smith'),('John','Doe'),('Jane','Doe');
.

自己結合をすることですべてのペアを入手できます。

select
    a.FirstName, a.LastName, b.FirstName, b.LastName
from @t as a
cross apply @t as b;
.

CROSS APPLYを使用して、HOOPSを通過してON句の結合条件を見つける必要があります。

次に数える必要があります。これがCASEステートメントが入ってきた場所です。ケースは、最初の名前のペアごとに整数値を返します。これはカウントされるものです。(最後の質問が一致するようにあなたの質問を正しく読んでいるなら、それが私が持っている比較です。うまくいけば、私が間違っているならばこれを修正する方法は明らかです。)

select
    ...
    case
        when a.LastName = b.LastName then 1
        else 0
    end
...etc.
.

SUM()GROUP BYで追加し、あなたはあなたの答えを得る:

select
    a.FirstName,
    b.FirstName,
    sum(
    case
        when a.LastName = b.LastName then 1
        else 0
    end
    ) as CommonLastNames
from @t as a
cross apply @t as b
group by a.FirstName, b.FirstName;
.

他のヒント

私は私の質問を認めなければなりませんでした少し欠陥がありました。 私が本当に必要なのは、最初の最初の名前からの最初のFirstNameのペアでは、「共通のLastNameの数」を含んでいませんでした。実際、私はゼロカウントでペアを気にしません。

質問が修正されると、解ははるかに速くなります。

入力を与えた:

create local temp table t (FirstName char(10), LastName char(10)) ON COMMIT PRESERVE ROWS;
insert into t(FirstName,LastName) values ('John','Smith');
insert into t(FirstName,LastName) values ('John','Doe');
insert into t(FirstName,LastName) values ('Jane','Doe');
.

元の質問の場合、解決策はO(n ^ 2)です(質問が「すべてのペア」を主張するため):

select a.FirstName, b.FirstName, 
  sum(case when a.LastName = b.LastName then 1 else 0 end) CommonNames 
  from t a, t b group by 1, 2;
.

ゼロカウントをスキップするのが問題ない場合、LastNameの自己結合は、はるかに速く機能します(データが十分に疎になると仮定):

select a.FirstName, b.FirstName,
  count(*) CommonNames from t a
  join t b using (LastName) group by 1, 2;
.

私はまだこの些細な解決策を逃したのだろうか。

DOH!これが良い方法です:

SELECT city_a, city_b, COUNT(*)
    FROM (
        SELECT a.city city_a,
               a.state,
               b.city city_b
        FROM       us a
        CROSS JOIN us b
        WHERE a.state = b.state
          AND a.city < b.city
         ) x
    GROUP BY city_a, city_b
    ORDER BY 3 DESC;
.

出力:

+-----------+-------------+----------+
| city_a    | city_b      | COUNT(*) |
+-----------+-------------+----------+
| Lebanon   | Springfield |        5 |
| Bedford   | Franklin    |        4 |  -- as shown in previous 'answer'
| Franklin  | Lebanon     |        4 |
| Franklin  | Hudson      |        4 |
| Franklin  | Salem       |        4 |
| Hudson    | Salem       |        4 |
| Salem     | Springfield |        4 |
| Clinton   | Columbia    |        4 |
| Auburn    | Fairfield   |        3 |
| Auburn    | Madison     |        3 |
...
(2.63 sec) -- for all 4175 cities in `us`.
.

Synity On First Item:

mysql> SELECT city, state FROM us WHERE city IN ('Lebanon', 'Springfield');
+-------------+-------+
| city        | state |
+-------------+-------+
| Springfield | FL    |
| Springfield | IL    |
| Lebanon     | IN    |
| Springfield | MA    |
| Lebanon     | ME    |
| Lebanon     | MO    |
| Springfield | MO    |
| Lebanon     | NH    |
| Springfield | NJ    |
| Lebanon     | OH    |
| Springfield | OH    |
| Lebanon     | OR    |
| Springfield | OR    |
| Lebanon     | PA    |
| Springfield | PA    |
| Lebanon     | TN    |
| Springfield | TN    |
| Springfield | VA    |
| Springfield | VT    |
+-------------+-------+
19 rows in set (0.00 sec)
.

メインハンドラ%ステータス値は、それが多くの作業をしたが、かなりo(n * n)ではないことを示しています(おそらくクロスジョインは一度に1つの状態だけなので)

| Handler_read_key           | 4176   |
| Handler_read_next          | 667294 |
| Handler_read_rnd           | 1742   |
| Handler_read_rnd_next      | 701964 |
| Handler_update             | 1731   |
| Handler_write              | 703693 |
.

百万の列への外挿 - それはおそらく数日かかるでしょう。

それは興味深い挑戦でした。米国の都市のリストを使用して、私はこの解決策を思いつきました(MySQLで):

SELECT  city_a, city_b,
        COUNT(DISTINCT state)
    FROM (
        ( SELECT a.city city_a,
                 b.city city_b,
                 a.state            -- This line differs
            FROM       us a
            CROSS JOIN us b
            WHERE a.state = b.state
              AND a.city != b.city   -- Added (to avoid noise)
              AND a.city < 'M'    -- to speed up test
              AND b.city < 'M'
        )
        UNION ALL
        ( SELECT a.city city_a,
                 b.city city_b,
                 b.state            -- This line differs
            FROM       us a
            CROSS JOIN us b
            WHERE a.state = b.state
              AND a.city != b.city   -- Added (to avoid noise)
              AND a.city < 'M'    -- to speed up test
              AND b.city < 'M'
        )
        ) ab
    GROUP BY 1, 2
    HAVING   COUNT(DISTINCT state) > 1
    ORDER BY COUNT(DISTINCT state) desc

INDEX(state, city) パフォーマンスに役立ちます。

その結果は以下の通りです:

+----------+------------+-----------------------+
| city_a   | city_b     | COUNT(DISTINCT state) |
+----------+------------+-----------------------+
| Franklin | Bedford    |                     4 |
| Lebanon  | Franklin   |                     4 |
| Franklin | Lebanon    |                     4 |
| Hudson   | Franklin   |                     4 |
| Columbia | Clinton    |                     4 |
| Clinton  | Columbia   |                     4 |
| Franklin | Hudson     |                     4 |
| Bedford  | Franklin   |                     4 |
| Lebanon  | Farmington |                     3 |
| Hanover  | Kingston   |                     3 |
...
(25.17 sec)

アルファベット全体を含めるのに4倍の時間がかかったかもしれません。テーブルには4K行しかなかったので、これは次のとおりです ない 速い仕事。

結果の「証明」:mysql>SELECT city,state FROM us where city IN('Franklin','Bedford');

+----------+-------+
| city     | state |
+----------+-------+
| Bedford  | IN    |
| Franklin | IN    |
| Bedford  | MA    |
| Franklin | MA    |
| Bedford  | NH    |
| Franklin | NH    |
| Bedford  | OH    |
| Franklin | OH    |
| Franklin | TN    |
| Bedford  | TX    |
| Franklin | WI    |
+----------+-------+
11 rows in set (0.00 sec)
ライセンス: CC-BY-SA帰属
所属していません dba.stackexchange
scroll top