2

より明確にするために編集 - 元の例の混乱について多くの謝罪

夫婦を表す次のテーブル構造があります。

id | Person | Spouse
______________________
1  | Mary   | John
2  | John   | Mary
3  | Katy   | Bob
4  | Bob    | Katy
5  | Mary   | John
6  | John   | Mary

この例では、メアリーはジョンと結婚し、ケイティはボブと結婚し、のメアリーは別のジョンと結婚しています。

これらの夫婦のペアを取得するにはどうすればよいですか?

私はこれに近づきました:

SELECT 
  p.id id1,
  q.id id2
FROM 
  people p 
  INNER JOIN people q ON
    p.person = q.spouse AND 
    q.person = p.spouse AND 
    p.id < q.id
ORDER BY p.id

ただし、これは次を返します。

1 | 2 (1st Mary & 1st John)
1 | 6 (1st Mary & 2nd John) *problem*
2 | 5 (1st John & 2nd Mary) *problem*
3 | 4 (Katy & Bob)
5 | 6 (2nd Mary & 2nd John)

1st Mary と 1st John が 1 回だけ結婚していることを確認するにはどうすればよいですか (つまり、上記の問題行を削除します)。

どうもありがとう

この例を作成するための SQL は次のとおりです。

CREATE TABLE people
    (`id` int, `person` varchar(7), `spouse` varchar(7))
;

INSERT INTO people
    (`id`, `person`, `spouse`)
VALUES
    (1, 'Mary', 'John'),
    (2, 'John', 'Mary'),
    (3, 'Katy', 'Bob'),
    (4, 'Bob', 'Katy'),
    (5, 'Mary', 'John'),
    (6, 'John', 'Mary')
;

SELECT 
  p.id id1,
  q.id id2
FROM 
  people p 
  INNER JOIN people q ON
    p.person = q.spouse AND 
    q.person = p.spouse AND 
    p.id < q.id
ORDER BY p.id
;
4

5 に答える 5

1

試してみます:

SELECT
  p.id AS id1,
  q.id AS id2
FROM
  people AS p 
  JOIN people AS q ON
    p.person = q.spouse AND 
    q.person = p.spouse AND 
    p.id < q.id
  JOIN (SELECT 
          p.id, COUNT(*) AS rank
        FROM 
          people AS p 
          INNER JOIN people AS p2 ON
            p.person = p2.person AND 
            p.spouse = p2.spouse AND 
            p.id >= p2.id
        GROUP BY p.id
       ) AS x ON
    x.id = p.id
  JOIN (SELECT 
          p.id, COUNT(*) AS rank
        FROM 
          people AS p 
          INNER JOIN people AS p2 ON
            p.person = p2.person AND 
            p.spouse = p2.spouse AND 
            p.id >= p2.id
        GROUP BY p.id
       ) AS y ON
    y.id = q.id AND
    y.rank = x.rank ;

そしてもう1つ:

SELECT
  p.id AS id1,
  q.id AS id2
FROM
  people AS p 
  JOIN people AS q ON
    p.person = q.spouse AND 
    q.person = p.spouse
  JOIN people AS p2 ON
    p.person = p2.person AND 
    p.spouse = p2.spouse AND 
    p.id >= p2.id
  JOIN people AS q2 ON
    q.person = q2.person AND 
    q.spouse = q2.spouse AND 
    q.id >= q2.id
WHERE 
    p.id < q.id
GROUP BY 
    p.id, q.id
HAVING 
    COUNT(DISTINCT p2.id) = COUNT(DISTINCT q2.id) ;

両方ともSQL-Fiddleでテスト済み

MySQLだけがウィンドウ関数を持っていれば(他のほとんどすべてのDBMSが持っているように)、はるかに簡単になります。Postgresフィドルでテスト済み:

WITH cte AS
  ( SELECT
        id, person, spouse, 
        ROW_NUMBER() OVER( PARTITION BY person, spouse 
                           ORDER BY id )
           AS rn
    FROM
        people
  ) 
SELECT
    p.id AS id1,
    q.id AS id2 
FROM
  cte AS p
  JOIN cte AS q ON
    p.person = q.spouse AND 
    q.person = p.spouse AND
    p.rn = q.rn AND
    p.id < q.id ;
于 2013-03-17T00:55:09.950 に答える
1

この例では、メアリーはジョンと結婚し、ケイティはボブと結婚し、別のメアリーはリチャードと結婚しています。

ショーのデータ構造では、これら 2 つの「Mary」を区別することはできませ。両者の間に違いはないからです。

どちらも単なるテキスト リテラルMaryです。同じ名前を持つ可能性のあるさまざまな人々を区別したい場合は、別の基準と、その上で一意の基準が必要です。(各個人のデータベース レコードのIDを指定します。)

于 2013-03-16T22:43:59.003 に答える
0

データベースの制限が間違っています。

メアリー、ジョンなどのような人々はアイデンティティを持っていません。

ヒューリスティッククエリが役立つ場合がありますが、信頼できるソリューションではありません。

したがって、データ構造を改善してください。

于 2013-03-17T01:55:49.410 に答える
-1

それを行う方法はたくさんありますが、データベースを使用する最も重要な理由の1つは、データベースが大量のデータを保持していることです。また、大量のデータを取得するクエリを作成することはめったにありません。非常に珍しい状況を除いて、宿題の場合は、いくつかの基準に従って結果をフィルタリングする必要があります。したがって、最も適切な解決策は、後でクエリに追加する他のものによって異なります。

ただし、一意のペアを取得する方法の例をいくつか示します。

SELECT a, b, GROUP_CONCAT(id)
(SELECT id
, IF (person>=spouse, person, spouse) as a
, IF (person>=spouse, spouse, person) as b
FROM yourtable ) AS pairs
GROUP BY a,b;

SELECT id, person, spouse
FROM yourtable s1
WHERE NOT EXISTS ( SELECT 1
    FROM yourtable s2
    WHERE s2.id>s1.id
    AND s1.person=s2.spouse
    AND s1.spouse=S2.person);

(他にもいくつかの解決策があります)。

于 2013-03-16T23:41:39.497 に答える
-1

あまりエレガントではありませんが、機能します:

SELECT p.id, q.id
FROM people p
INNER JOIN people q ON
p.person1 = q.person2 and 
q.person1 = p.person1

実際には、反転された行の存在をセレクターとして使用します

于 2013-03-16T22:54:14.247 に答える