0

テーブル(T1)と属性を持つテーブル(T2)があります。提供されたIDを持つレコードと同じ属性を持つレコードを探しています。

これが例です。1が与えられた場合、2を見つけたい(属性も一致することを確認する)。

T1
ID | A | B
----------
1  | k | l
2  | k | l


T2
IDFK | C | D
-------------    
1    | w | x
1    | y | z
2    | w | x
2    | y | z

これが私がこれまでに持っているSQLです:

SELECT * FROM T1 
JOIN T1 AS T1COPY ON T1.A = T1COPY.A, T1.B = T1COPY.B 
JOIN T2 ON T1.ID = T2.IDFK 
JOIN T2 AS T2COPY ON T1COPY.ID = T2COPY.IDFK 
   AND T2.C = T2COPY.C 
   AND T2.D = T2COPY.D
WHERE T1.ID = 1

ただし、属性が異なっていても2に一致するため、正しく機能していません。

4

7 に答える 7

1

MySQLの答えは次のとおりです:http ://www.sqlfiddle.com/#!2/ec4fa/2

select h.* 
from 
(
    select x.*
    from t join t x using(a,b)
    where t.id = 1 and x.id <> 1  
) h
join 
(

    select coalesce(x.cpIdFk, x.uIdFk) as idFk  
    from
    (
      select cp.idFk as cpIdFk, u.idFk as uIdFk
      from 
      (
        select t.id as idFk, x.*
        from t cross join (select c, d from u where idFk = 1) as x
        where t.id <> 1      
      ) cp
      left join (select * from u where idFk <> 1) u using(idfk,c,d)

      union

      select cp.idFk,u.idFk
      from 
      (
        select t.id as idFk, x.*
        from t cross join (select c, d from u where idFk = 1) as x
        where t.id <> 1      
      ) cp
      right join (select * from u where idFk <> 1) u using(idfk,c,d)

    ) as x

    group by idFk
    having bit_and(cpidFk is not null and uIdFk is not null)

) d on d.idFk = h.id 
order by h.id;

フィルタIDの出力==1:

| ID | A | B |
--------------
|  2 | k | l |
|  5 | k | l |

これらの入力から:

CREATE TABLE t
    (ID int, A varchar(1), B varchar(1));

INSERT INTO t
    (ID, A, B)
VALUES
    (1, 'k', 'l'),
    (2, 'k', 'l'),
    (3, 'k', 'l'),
    (4, 'k', 'l'),
    (5, 'k', 'l'),
    (6, 'k', 'j');


CREATE TABLE u
    (IDFK int, C varchar(1), D varchar(1));

INSERT INTO u
    (IDFK, C, D)
VALUES
    (1, 'w', 'x'),
    (1, 'y', 'z'),

    (2, 'w', 'x'),
    (2, 'y', 'z'),

    (3, 'w', 'x'),
    (3, 'y', 'z'),
    (3, 'm', 'z'),

    (4, 'w', 'x'),

    (5, 'w', 'x'),
    (5, 'y', 'z'),

    (6, 'w', 'x'),
    (6, 'y', 'z');

ここでの説明:複数のテーブル間で重複を検索する

MySQLクエリは、完全結合をサポートしておらず、CTEも備えていないため、少し複雑に見えます。とFULL JOINの結果を結合することによってシミュレートしますLEFT JOINRIGHT JOIN

于 2012-08-20T08:04:55.510 に答える
0

入力IDを表す属性データを定義することから始めましょう。

select idfk, c, d
from t2
where idfk = @ID

これで、この情報を使用して、IDFKが@IDではないT2に存在する潜在的な一致を選択できます。

select x.idfk, x.c, x.d y.idfk as id2 from (
    select idfk, c, d
    from t2
    where idfk = @ID
) x left join t2 y on x.c = y.c and x.d = y.d
where y.idfk <> @ID 
  and y.idfk is not null

id2の各値の行数が最初のクエリの行数と同じである場合、データは2番目のクエリが最初のクエリのデータと適切に一致します。

したがって:

select id2 from ( 
    select id2, count(*) as rowcount from (
        <second query>
    ) z
) rowsByID
where rowcount = (select count(*) from (<first query>) IDattributes)

返された行がAとBでも一致する必要があるのか​​、それとも表2のデータだけで一致するのかはわかりませんが、AとBで一致する必要があると仮定すると、次のようになります。

select ID from t1 
    join <third query> m on t1.id = m.id2
    join (select a, b from t1 where id = @id) prime_row on t1.a = prime_row.a and t1.b = prime_row.b

一致させるためにAとBが必要ない場合は、2番目の結合をドロップします。

どう?

于 2012-08-19T23:06:39.177 に答える
0

これは、大きなテーブルではおそらく信じられないほど遅くなるでしょう。(編集:mysqlでは完全結合を使用できないことがわかりました。ただし、最初のクエリは他のシステムでも有効であり、理解しやすい可能性があります。気にしない場合は、2番目のクエリにスキップしてください。)

パラメータマーカーとして疑問符を使用しました。すべてが一致する「重複」IDの同じ値を受け取る必要があります。and T.id <> ?結果セットから一致する行を除外する条件を追加します。(OPは1行目と2行目の両方が必要だと思っていました。)tXは検索スペースを表すため、そこで除外して、プロセスの早い段階で削除することもできます。

select *
from T1 as T
where T.id in (
    select coalesce(attrR.idfk, tX.id)
    from
        T1 as tX
        cross join
        (select * from T2 where T2.idfk = ?) as attrL
        full outer join T2 as attrR
            on      attrR.idfk = tX.id
                and attrR.c = attrL.c
                and attrR.d = attrL.d
    group by coalesce(attrR.idfk, tX.id)
    having count(*) =
        sum(case
                when attrR.c = attrL.c and attrR.d = attrL.d
                then 1 else 0
            end
        )
);

これはの欠如を回避しfull outer joinます。

select *
from T1 as T
where T.id in (
    select attrR.idfk
    from
        T1 as tX
        cross join
        (select * from T2 where idfk = ?) as attrL
        right outer join
        T2 as attrR
            on      attrR.idfk = tX.id
                and attrR.c = attrL.c
                and attrR.d = attrL.d
        cross join
        (select count(*) as cnt from T2 where idfk = ?) as tC
    group by attrR.idfk
    having
        sum(case
                when attrR.c = attrL.c and attrR.d = attrL.d
                then 1 else 1000000
            end
        ) = min(tC.cnt)
);

sum(case...)この複合チェックは、式と同等です。片方がもう片方より気分が良いかもしれません。

    having
            count(attrL.idfk) = min(tC.cnt)
        and count(*) = min(tC.cnt)

私が提供した最初と2番目のクエリは機能しますが、各T1がT2に少なくとも1つの属性を持っている場合に限ります。これは、ダミー属性を追加して、それを台無しにする中間結果の空のセットを防ぐことによって補正するバージョンです。醜いので、その場合に必要でない場合は使用しないでください。(完全結合バージョンでも同様の調整が必要です。)

select *
from T1 as T
where T.id in (
    select attrR.idfk
    from
        T1 as tX
        cross join
        (
            select c, d from T2 where idfk = ?
            union all
            select '!@#$%', '' -- add a dummy attribute
        ) as attrL
        right outer join
        (
            select idfk, c, d from T2
            union all
            select id, '!@#$%', '' from T1
        ) as attrR
            on      attrR.idfk = tX.id
                and attrR.c = attrL.c
                and attrR.d = attrL.d
        cross join
        (select count(*)+1 as cnt from T2 where idfk = ?) as tC -- note the +1
    group by attrR.idfk
    having
            count(tX.id) = min(tC.cnt)
        and count(*) = min(tC.cnt)
);
于 2012-08-20T01:50:04.057 に答える
0

2番目の改訂された回答

コメントには、T2に重複する行が存在する可能性があると記載されているため、さらに複雑なソリューションが必要です。これが正しいデータを生成すると私が信じるクエリです。

-- Query 8B
SELECT x.id
  FROM (SELECT d2.id, d2.c, d2.d
          FROM (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk != 1) AS d2
          JOIN (SELECT id
                  FROM (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk != 1) AS x
                 GROUP BY id
                HAVING COUNT(*) = (SELECT COUNT(*)
                                     FROM (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk  = 1) AS x
                                    GROUP BY id)
               ) AS j2
            ON j2.id = d2.id
       ) AS x
  JOIN (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk  = 1) AS y
    ON x.c = y.c AND x.d = y.d
 GROUP BY x.id
HAVING COUNT(*) = (SELECT COUNT(*)
                     FROM (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk  = 1) AS x
                    GROUP BY id);

それが可能な限り単純であるかどうかは疑問ですが、それは以前に改訂された回答の論理的な続きです。

実行例

これは、開発された手順を示すクエリのトレース出力です。DBMSは、Mac OSX10.7.4で実行されるIBMInformixDynamic Server 11.70.FC2であり、SQLコマンドインタープリターとしてSQLCMD v88.00を使用します(いいえ、Microsoftのjohnny-come-latelyではありません。20年以上前に最初に作成したものです)。 。

+ BEGIN;
+ CREATE TABLE T1
(ID INTEGER NOT NULL PRIMARY KEY, a CHAR(1) NOT NULL, b CHAR(1) NOT  NULL);
+ INSERT INTO T1 VALUES(1, 'k', 'l');
+ INSERT INTO T1 VALUES(2, 'k', 'l');
+ INSERT INTO T1 VALUES(3, 'a', 'b');
+ INSERT INTO T1 VALUES(4, 'p', 'q');
+ INSERT INTO T1 VALUES(5, 't', 'v');
+ CREATE TABLE T2
(IDFK INTEGER NOT NULL REFERENCES T1, c CHAR(1) NOT NULL, d CHAR(1) NOT  NULL);
+ INSERT INTO T2 VALUES(1, 'w', 'x');
+ INSERT INTO T2 VALUES(1, 'y', 'z');
+ INSERT INTO T2 VALUES(2, 'w', 'x');
+ INSERT INTO T2 VALUES(2, 'w', 'x');
+ INSERT INTO T2 VALUES(2, 'y', 'z');
+ INSERT INTO T2 VALUES(3, 'w', 'x');
+ INSERT INTO T2 VALUES(3, 'y', 'b');
+ INSERT INTO T2 VALUES(3, 'y', 'z');
+ INSERT INTO T2 VALUES(4, 'w', 'x');
+ INSERT INTO T2 VALUES(5, 'w', 'x');
+ INSERT INTO T2 VALUES(5, 'y', 'z');
+ INSERT INTO T2 VALUES(5, 'w', 'x');
+ INSERT INTO T2 VALUES(5, 'y', 'z');
+ SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk != 1;
2|w|x
2|y|z
3|w|x
3|y|b
3|y|z
4|w|x
5|w|x
5|y|z
+ SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk  = 1;
1|w|x
1|y|z
+ SELECT id, COUNT(*) FROM (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk != 1) AS x GROUP BY id;
2|2
5|2
3|3
4|1
+ SELECT id, COUNT(*) FROM (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk  = 1) AS x GROUP BY id;
1|2
+ -- Query 5B - IDs having same count of distinct rows as ID = 1
SELECT id
  FROM (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk != 1) AS x
 GROUP BY id
HAVING COUNT(*) = (SELECT COUNT(*)
                     FROM (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk  = 1) AS x
                    GROUP BY id);
2
5
+ -- Query 6B
SELECT d2.id, d2.c, d2.d
  FROM (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk != 1) AS d2
  JOIN (SELECT id
          FROM (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk != 1) AS x
         GROUP BY id
        HAVING COUNT(*) = (SELECT COUNT(*)
                             FROM (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk  = 1) AS x
                            GROUP BY id)
       ) AS j2
    ON j2.id = d2.id
 ORDER BY id;
2|w|x
2|y|z
5|w|x
5|y|z
+ -- Query 7B
SELECT x.id, y.id, x.c, y.c, x.d, y.d
  FROM (SELECT d2.id, d2.c, d2.d
          FROM (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk != 1) AS d2
          JOIN (SELECT id
                  FROM (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk != 1) AS x
                 GROUP BY id
                HAVING COUNT(*) = (SELECT COUNT(*)
                                     FROM (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk  = 1) AS x
                                    GROUP BY id)
               ) AS j2
            ON j2.id = d2.id
       ) AS x
  JOIN (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk  = 1) AS y
    ON x.c = y.c AND x.d = y.d
 ORDER BY x.id, y.id, x.c, x.d;
2|1|w|w|x|x
2|1|y|y|z|z
5|1|w|w|x|x
5|1|y|y|z|z
+ -- Query 8B
SELECT x.id
  FROM (SELECT d2.id, d2.c, d2.d
          FROM (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk != 1) AS d2
          JOIN (SELECT id
                  FROM (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk != 1) AS x
                 GROUP BY id
                HAVING COUNT(*) = (SELECT COUNT(*)
                                     FROM (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk  = 1) AS x
                                    GROUP BY id)
               ) AS j2
            ON j2.id = d2.id
       ) AS x
  JOIN (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk  = 1) AS y
    ON x.c = y.c AND x.d = y.d
 GROUP BY x.id
HAVING COUNT(*) = (SELECT COUNT(*)
                     FROM (SELECT DISTINCT idfk AS id, c, d FROM t2 WHERE idfk  = 1) AS x
                    GROUP BY id);
2
5
+ ROLLBACK;

最初に改訂された回答

ステップ1:ID=1と同じ行数のID

SELECT idfk AS id -- Query 5
  FROM t2
 WHERE idfk != 1
 GROUP BY idfk
HAVING COUNT(*) = (SELECT COUNT(*) FROM t2 WHERE t2.idfk = 1);

ステップ2:クエリ5に対応するデータ

SELECT idfk AS id, c, d -- Query 6
  FROM t2
  JOIN (SELECT idfk AS id
          FROM t2
         WHERE idfk != 1
         GROUP BY idfk
        HAVING COUNT(*) = (SELECT COUNT(*) FROM t2 WHERE t2.idfk = 1)
       ) AS j2
    ON j2.id = t2.idfk
 ORDER BY id;

ステップ3:クエリ6の行をID=1の行と結合します

SELECT x.id, y.id, x.c, y.c, x.d, y.d -- Query 7
  FROM (SELECT idfk AS id, c, d
          FROM t2
          JOIN (SELECT idfk AS id
                  FROM t2
                 WHERE idfk != 1
                 GROUP BY idfk
                HAVING COUNT(*) = (SELECT COUNT(*) FROM t2 WHERE t2.idfk = 1)
               ) AS j2
            ON j2.id = t2.idfk
       ) AS x
  JOIN (SELECT idfk AS id, c, d
          FROM t2 WHERE idfk = 1
       ) AS y
    ON x.c = y.c AND x.d = y.d
 ORDER BY x.id, y.id, x.c, x.d;

ステップ4:カウントがID=1のカウントと同じであるクエリ7からのID

SELECT x.id
  FROM (SELECT idfk AS id, c, d
          FROM t2
          JOIN (SELECT idfk AS id
                  FROM t2
                 WHERE idfk != 1
                 GROUP BY idfk
                HAVING COUNT(*) = (SELECT COUNT(*) FROM t2 WHERE t2.idfk = 1)
               ) AS j2
            ON j2.id = t2.idfk
       ) AS x
  JOIN (SELECT idfk AS id, c, d
          FROM t2 WHERE idfk = 1
       ) AS y
    ON x.c = y.c AND x.d = y.d
 GROUP BY x.id
HAVING COUNT(*) = (SELECT COUNT(*) FROM t2 WHERE t2.idfk = 1);

実行例

DBMSは、Mac OSX10.7.4で実行されるIBMInformixDynamic Server 11.70.FC2であり、SQLコマンドインタープリターとしてSQLCMD v88.00を使用します(いいえ、Microsoftのjohnny-come-latelyではありません。20年以上前に最初に作成したものです)。 。

+ BEGIN;
+ CREATE TABLE T1
(ID INTEGER NOT NULL PRIMARY KEY, a CHAR(1) NOT NULL, b CHAR(1) NOT  NULL);
+ INSERT INTO T1 VALUES(1, 'k', 'l');
+ INSERT INTO T1 VALUES(2, 'k', 'l');
+ INSERT INTO T1 VALUES(3, 'a', 'b');
+ INSERT INTO T1 VALUES(4, 'p', 'q');
+ CREATE TABLE T2
(IDFK INTEGER NOT NULL REFERENCES T1, c CHAR(1) NOT NULL, d CHAR(1) NOT  NULL);
+ INSERT INTO T2 VALUES(1, 'w', 'x');
+ INSERT INTO T2 VALUES(1, 'y', 'z');
+ INSERT INTO T2 VALUES(2, 'w', 'x');
+ INSERT INTO T2 VALUES(2, 'y', 'z');
+ INSERT INTO T2 VALUES(3, 'w', 'x');
+ INSERT INTO T2 VALUES(3, 'y', 'b');
+ INSERT INTO T2 VALUES(3, 'y', 'z');
+ INSERT INTO T2 VALUES(4, 'w', 'x');
+ SELECT t1.id AS id, t2.c, t2.d -- Query 1
  FROM t1
  JOIN t2 ON t1.id = t2.idfk;
1|w|x
1|y|z
2|w|x
2|y|z
3|w|x
3|y|b
3|y|z
4|w|x
+ -- Query 5 - IDs having same count of rows as ID = 1

SELECT idfk AS id
  FROM t2
 WHERE idfk != 1
 GROUP BY idfk
HAVING COUNT(*) = (SELECT COUNT(*) FROM t2 WHERE t2.idfk = 1);
2
+ SELECT idfk AS id, c, d
  FROM t2
  JOIN (SELECT idfk AS id
          FROM t2
         WHERE idfk != 1
         GROUP BY idfk
        HAVING COUNT(*) = (SELECT COUNT(*) FROM t2 WHERE t2.idfk = 1)
       ) AS j2
    ON j2.id = t2.idfk
 ORDER BY id;
2|w|x
2|y|z
+ SELECT x.id, y.id, x.c, y.c, x.d, y.d
  FROM (SELECT idfk AS id, c, d
          FROM t2
          JOIN (SELECT idfk AS id
                  FROM t2
                 WHERE idfk != 1
                 GROUP BY idfk
                HAVING COUNT(*) = (SELECT COUNT(*) FROM t2 WHERE t2.idfk = 1)
               ) AS j2
            ON j2.id = t2.idfk
       ) AS x
  JOIN (SELECT idfk AS id, c, d
          FROM t2 WHERE idfk = 1
       ) AS y
    ON x.c = y.c AND x.d = y.d
 ORDER BY x.id, y.id, x.c, x.d;
2|1|w|w|x|x
2|1|y|y|z|z
+ SELECT x.id
  FROM (SELECT idfk AS id, c, d
          FROM t2
          JOIN (SELECT idfk AS id
                  FROM t2
                 WHERE idfk != 1
                 GROUP BY idfk
                HAVING COUNT(*) = (SELECT COUNT(*) FROM t2 WHERE t2.idfk = 1)
               ) AS j2
            ON j2.id = t2.idfk
       ) AS x
  JOIN (SELECT idfk AS id, c, d
          FROM t2 WHERE idfk = 1
       ) AS y
    ON x.c = y.c AND x.d = y.d
 GROUP BY x.id
HAVING COUNT(*) = (SELECT COUNT(*) FROM t2 WHERE t2.idfk = 1);
2
+ ROLLBACK;

元の回答

これにより、少なくとも質問が十分に明確になりました。

私が知る限り、次のようなサブクエリがある場合:

SELECT t1.id AS id, t2.c, t2.d  -- Query 1
  FROM t1
  JOIN t2 ON t1.id = t2.idfk

c次に、との値はd同じであるがid値が異なる結果セット内の行のペアを探しています。したがって、それに基づいてメインクエリを記述します。

SELECT j1.id, j2.id  -- Query 2
  FROM (SELECT t1.id AS id, t2.c, t2.d
          FROM t1
          JOIN t2 ON t1.id = t2.idfk
       ) AS j1
  JOIN (SELECT t1.id AS id, t2.c, t2.d
          FROM t1
          JOIN t2 ON t1.id = t2.idfk
       ) AS j2
    ON j1.c = j2.c AND j1.d = j2.d AND j1.id != j2.id

!=条件をまたはのいずれかに<変更することで、「1、2」と「2、1」の両方を取得しないようにすることができます>

T1の特定のID値に一致する行が必要な場合は、WHERE句で指定できます。

SELECT j2.id  -- Query 3
  FROM (SELECT t1.id AS id, t2.c, t2.d
          FROM t1
          JOIN t2 ON t1.id = t2.idfk
       ) AS j1
  JOIN (SELECT t1.id AS id, t2.c, t2.d
          FROM t1
          JOIN t2 ON t1.id = t2.idfk
       ) AS j2
    ON j1.c = j2.c AND j1.d = j2.d AND j1.id != j2.id
 WHERE j1.id = 1;  -- 1 is the ID for which matches are sought

必要に応じて、サブクエリに条件を追加できます(ただし、優れたオプティマイザがそれを実行できる場合があります)。

SELECT j2.id  -- Query 4
  FROM (SELECT t1.id AS id, t2.c, t2.d
          FROM t1
          JOIN t2 ON t1.id = t2.idfk AND t1.id = 1
       ) AS j1
  JOIN (SELECT t1.id AS id, t2.c, t2.d
          FROM t1
          JOIN t2 ON t1.id = t2.idfk AND t1.id != 1
       ) AS j2
    ON j1.c = j2.c AND j1.d = j2.d
 WHERE j1.id = 1;  -- 1 is the ID for which matches are sought

メインのON句の3番目の条件は冗長でした。これは、構造上、サブクエリのID値j1がすべて1であり、サブクエリのID値j2がすべて「1ではない」ためです。


t2.idSQLのvsの問題を修正し、t2.idfk上記の4つのクエリを実行しました。それぞれが私が期待する答えを生み出します。たとえば、クエリ4の結果セットには2つの行があります。これは、T1に2組の行があり、T2に行{1、 ab }と{2、ab }の両方が存在するためです。一致する行が多数あるにもかかわらず、2つだけを1回だけ表示したい場合は、SELECTにDISTINCTを適用する必要があります。

コメントで、あなたは言います:

残念ながら、属性の1つが一致しなくても、結果が返されます。T2のすべての属性を一致させる方法は?

それを実証するには、拡張データセットが必要です。追加したとき:

INSERT INTO T1 VALUES(3, 'a', 'b');
INSERT INTO T2 VALUES(3, 'a', 'z');
INSERT INTO T2 VALUES(3, 'y', 'b');

値3は、クエリ1の結果にのみ表示されます。これは、表示される唯一の場所です。

サンプルデータを示して、あなたが間違った行動として見ているものを説明してください。上記のクエリを次のSQLとインターリーブされたクエリ結果でテストしました。DBMSは、Mac OSX10.7.4で実行されるIBMInformixDynamic Server 11.70.FC2であり、SQLコマンドインタープリターとしてSQLCMDv88.00を使用します。

+ BEGIN;
+ CREATE TEMP TABLE T1
(ID INTEGER NOT NULL PRIMARY KEY, A CHAR(1) NOT NULL, B CHAR(1) NOT  NULL);
+ INSERT INTO T1 VALUES(1, 'k', 'l');
+ INSERT INTO T1 VALUES(2, 'k', 'l');
+ INSERT INTO T1 VALUES(3, 'a', 'b');
+ CREATE TEMP TABLE T2
(IDFK INTEGER NOT NULL, C CHAR(1) NOT NULL, D CHAR(1) NOT  NULL);
+ INSERT INTO T2 VALUES(1, 'w', 'x');
+ INSERT INTO T2 VALUES(1, 'y', 'z');
+ INSERT INTO T2 VALUES(2, 'w', 'x');
+ INSERT INTO T2 VALUES(2, 'y', 'z');
+ INSERT INTO T2 VALUES(3, 'a', 'z');
+ INSERT INTO T2 VALUES(3, 'y', 'b');
+ SELECT t1.id AS id, t2.c, t2.d -- Query 1
  FROM t1
  JOIN t2 ON t1.id = t2.idfk;
1|w|x
1|y|z
2|w|x
2|y|z
3|a|z
3|y|b
+ SELECT j1.id, j2.id -- Query 2
  FROM (SELECT t1.id AS id, t2.c, t2.d
          FROM t1
          JOIN t2 ON t1.id = t2.idfk
       ) AS j1
  JOIN (SELECT t1.id AS id, t2.c, t2.d
          FROM t1
          JOIN t2 ON t1.id = t2.idfk
       ) AS j2
    ON j1.c = j2.c AND j1.d = j2.d AND j1.id != j2.id;
1|2
1|2
2|1
2|1
+ SELECT j2.id -- Query 3
  FROM (SELECT t1.id AS id, t2.c, t2.d
          FROM t1
          JOIN t2 ON t1.id = t2.idfk
       ) AS j1
  JOIN (SELECT t1.id AS id, t2.c, t2.d
          FROM t1
          JOIN t2 ON t1.id = t2.idfk
       ) AS j2
    ON j1.c = j2.c AND j1.d = j2.d AND j1.id != j2.id
 WHERE j1.id = 1;
2
2
+ SELECT j2.id  -- Query 4
  FROM (SELECT t1.id AS id, t2.c, t2.d
          FROM t1
          JOIN t2 ON t1.id = t2.idfk AND t1.id = 1
       ) AS j1
  JOIN (SELECT t1.id AS id, t2.c, t2.d
          FROM t1
          JOIN t2 ON t1.id = t2.idfk AND t1.id != 1
       ) AS j2
    ON j1.c = j2.c AND j1.d = j2.d
 WHERE j1.id = 1;
2
2
+ ROLLBACK;
于 2012-08-19T21:48:49.827 に答える
0

これに対する私のアプローチは、group_concatを使用して属性の2つの列を単一の値に結合することです。そうすれば、同じ属性を持つすべてのIDを簡単に見つけて、それらを属性として返すことができます。

select allts.id
from (select group_concat(c separator ';' order by c) as allcs,
             group_concat(d separator ';' order by d) as allds
      from t2
      where t2.id = 1
     ) t2_1 join
     (select t2.id, group_concat(c separator ';' order by c) as allcs,
             group_concat(d separator ';' order by d) as allds
      from t2
      group by t2.id
     ) allts
     on t2_1.allcs = allts.allcs and t2_1.allds = t2_1.allds join

このバージョンでは、t1の情報は考慮されていません。あなたの質問はt2の属性についてのみ言及しました。

于 2012-08-19T22:47:04.473 に答える
0

たまたまシステムをPostgresqlに移植する場合は、完全結合を使用できます:http ://www.sqlfiddle.com/#!1/1f0ef/1

with headers_matches as
(
    select x.*
    from t join t x using(a,b)
    where t.id = 1 and x.id <> 1
)
,cp as
(
    select t.id as idFk, x.*
    from t cross join (select c, d from u where idFk = 1) as x
    where t.id <> 1
)
,details_matches as
(
    select coalesce(cp.idFk,u.idFk) as idFk
    from cp
    full join (select * from u where idFk <> 1) u using(idfk,c,d)
    group by idFk
    having every(cp.idFk is not null and u.idFk is not null)
)
select h.* 
from headers_matches h
join details_matches d on d.idFk = h.id 
order by h.id;

フィルタIDの出力==1:

| ID | A | B |
--------------
|  2 | k | l |
|  5 | k | l |

これらの入力から:

CREATE TABLE t
    (ID int, A varchar(1), B varchar(1));

INSERT INTO t
    (ID, A, B)
VALUES
    (1, 'k', 'l'),
    (2, 'k', 'l'),
    (3, 'k', 'l'),
    (4, 'k', 'l'),
    (5, 'k', 'l'),
    (6, 'k', 'j');



CREATE TABLE u
    (IDFK int, C varchar(1), D varchar(1));

INSERT INTO u
    (IDFK, C, D)
VALUES
    (1, 'w', 'x'),
    (1, 'y', 'z'),

    (2, 'w', 'x'),
    (2, 'y', 'z'),

    (3, 'w', 'x'),
    (3, 'y', 'z'),
    (3, 'm', 'z'),

    (4, 'w', 'x'),

    (5, 'w', 'x'),
    (5, 'y', 'z'),

    (6, 'w', 'x'),
    (6, 'y', 'z');

使い方

最初に最も難しい部分、つまり詳細を行います。この回答の後半でヘッダーを作成します。

それがどのように機能するか、最初に詳細をクロスポピュレートする必要があります。これにより、詳細に対して適切な完全結合を実行できるため、ギャップを後で検出できます。

with cp as -- cross populate
(
    select t.id as idFk, x.*
    from t cross join (select c, d from u where idFk = 1) as x
    where t.id <> 1
)
select *
from cp;

出力:

| IDFK | C | D |
----------------
|    2 | w | x |
|    2 | y | z |
|    3 | w | x |
|    3 | y | z |
|    4 | w | x |
|    4 | y | z |
|    5 | w | x |
|    5 | y | z |
|    6 | w | x |
|    6 | y | z |

次に、そのクロスポピュレートされた詳細から、適切なFULLJOINを実行できます。

with cp as 
(
    select t.id as idFk, x.*
    from t cross join (select c, d from u where idFk = 1) as x
    where t.id <> 1
)
select 
    cp.idFk as cpIdFk, cp.c as cpC, cp.d as cpD,
    u.idFk as uFk, u.c as uC, u.d as Ud
from cp
full join (select * from u where idFk <> 1) u using(idfk,c,d);

出力:

| CPIDFK |    CPC |    CPD |    UFK |     UC |     UD |
-------------------------------------------------------
|      2 |      w |      x |      2 |      w |      x |
|      2 |      y |      z |      2 |      y |      z |
| (null) | (null) | (null) |      3 |      m |      z |
|      3 |      w |      x |      3 |      w |      x |
|      3 |      y |      z |      3 |      y |      z |
|      4 |      w |      x |      4 |      w |      x |
|      4 |      y |      z | (null) | (null) | (null) |
|      5 |      w |      x |      5 |      w |      x |
|      5 |      y |      z |      5 |      y |      z |
|      6 |      w |      x |      6 |      w |      x |
|      6 |      y |      z |      6 |      y |      z |

その情報が手元にあるので、2つのセットの間にギャップがあるかどうかを検出するための適切なロジックを実行できます。上記のセットから、ギャップのないものは#2、#5、および#6であることがわかります。そのために、このクエリを実行します。

with cp as
(
    select t.id as idFk, x.*
    from t cross join (select c, d from u where idFk = 1) as x
    where t.id <> 1
)
,details_matches as
(
    select coalesce(cp.idFk,u.idFk) as idFk
    from cp
    full join (select * from u where idFk <> 1) u using(idfk,c,d)
    group by idFk
    having every(cp.idFk is not null and u.idFk is not null)
)
select * from details_matches
order by idFk;

出力:

| IDFK |
--------
|    2 |
|    5 |
|    6 |

次に、ヘッダーの比較を行います。これは簡単です。

with headers_matches as
(
    select x.*
    from t join t x using(a,b)
    where t.id = 1 and x.id <> 1
)
select * from headers_matches;

ヘッダー#1のヘッダー値と同じであるため、ヘッダー#2、#3、#4、#5が返されます。

出力:

| ID | A | B |
--------------
|  2 | k | l |
|  3 | k | l |
|  4 | k | l |
|  5 | k | l |

最後に、2つのクエリを組み合わせます。

with headers_matches as
(
    select x.*
    from t join t x using(a,b)
    where t.id = 1 and x.id <> 1
)
,cp as
(
    select t.id as idFk, x.*
    from t cross join (select c, d from u where idFk = 1) as x
    where t.id <> 1
)
,details_matches as
(
    select coalesce(cp.idFk,u.idFk) as idFk
    from cp
    full join (select * from u where idFk <> 1) u using(idfk,c,d)
    group by idFk
    having every(cp.idFk is not null and u.idFk is not null)
)
select h.* 
from headers_matches h
join details_matches d on d.idFk = h.id 
order by h.id;

出力:

| ID | A | B |
--------------
|  2 | k | l |
|  5 | k | l |

ここでクエリの進行を参照してください:http ://www.sqlfiddle.com/#!1 / 1f0ef / 1

後でPostgresqlクエリをMysqlに変換します。

アップデート

MySQLのバージョンは次のとおりです。複数のテーブル間で重複を検索する

于 2012-08-20T02:27:36.223 に答える
0

私はあなたのコメントを通して私の前の答えを考えました、そして別のアプローチを提案するでしょう。

select idfk, c, d from t2 where idfk = @ID 

このクエリは、@IDのすべての属性セットを識別します。これを一時テーブルに入れ、このテーブルの各行について、T2のすべてのIDFKを識別するとします。IDFK<> @IDは、すべての属性値でソース行と一致します。これらすべての行を新しいテーブルに配置します。

これを行うための私のSQLは次のようになります:(これをmysqlに適合させる必要があるかもしれません)

create table #attribs (row# int, c, d);
insert #attribs (row#, c, d) values (0, null, null);

insert #attribs (row#, c, d)
select (select max row# from #attribs) + 1, c, d
from T2 where idfk = @ID;

delete #attribs where row# = 0;

create table #matchedattrib (idfk int)

while (select count(*) from #attribs) > 0 begin
    select @c = c, @d = d from #attribs where row# = (select min(row#) from #attribs);
    delete #attribs where row# = (select min(row#) from #attribs);

    insert #matchedattrib (idfk)
    select idfk from T2 where idfk <> @ID and T2.c = @c and T2.d = @d;
end

これを行うと、@ ID(最初のクエリ)の属性セットと同じ行数を持つこの新しいテーブルのIDFKには、@IDのすべての属性が含まれます。

select idfk, count(*) as tot_attribs
into #counts
from #matchedattrib
group by idfk
having count(*) = (select count(*) from (select idfk from T2 where idfk = @ID) x);

ただし、前の回答で指摘したように、これらのIDFKは他の属性も持つ可能性があるため、2番目のテーブルの行数が正しいIDFKの場合、T2に存在する行がこれと同じであることをカウントする必要があります。 number-これらの一致する属性が実際にそのIDFKのすべての属性であることを確認します-属性の完全な一致を意味します。

select idfk from #counts
where tot_attribs = (select count(*) from T2 where idfk = #counts.idfk)

A + Bでも一致させる必要がある場合は、自分で入力する必要があります。

于 2012-08-20T02:30:13.877 に答える