6

newby sql 関連の質問があります。

この単純なテーブルがあるとしましょう:

A      B
------ ------
a      b
a      c
b      a
m      n
m      o
n      m

「カウンターパート」のみを持つレコードをクエリしたい、つまり、テーブルにa bある場合にのみ取得b aしたいが、「バックリンク」(ここにある) をスキップしたいb a。要約すると、次の結果を得たいと思います

A       B
------  ------
a       b
m       n

このSQLクエリは、結果セットから削除された場合b aに処理されるため、機能しません。a b

SELECT DISTINCT x1.A, x1.B
FROM TEST x1, TEST x2
WHERE x1.A = x2.B AND x1.B = x2.A -- all records /w counterparts only
AND x1.A NOT IN (SELECT B from TEST where B = x1.A) -- skip the "back links"

WHERE 句の 2 番目の部分が期待どおりに機能しません。

ヒントはありますか?これについての助けをいただければ幸いです。

よろしくピーター

psダービーデータベースを使用しています。

4

7 に答える 7

6

最後の行を次のように変更できます。

AND x1.A < x1.B

これは、列が自己参照型ではないか(a、aなど)、循環参照を表示したくないことを前提としています。そうした場合、次のようになります。

AND x1.A <= x1.B

編集:

明示的な結合も使用したほうがよいでしょう。

SELECT DISTINCT 
    x1.A
    , x1.B
FROM 
    TEST x1
JOIN 
    TEST x2
    ON x1.A = x2.B 
        AND x1.B = x2.A -- all records /w counterparts only
WHERE x1.A < x1.B --Skip backreference
于 2012-11-21T16:54:53.683 に答える
1
SELECT Distinct
  case when tab1.A < tab1.B then tab1.A else tab1.B end as A,
  case when tab1.A > tab1.B then tab1.A else tab1.B end as B
FROM
  tab inner join tab tab1 on tab.B = tab1.A
WHERE
  tab1.B = tab.A

編集:更新された回答に基づいて、これが必要だと思います:

select distinct
  (case when tab1.A < tab1.B then tab1.A else tab1.B end) as A,
  (case when tab1.A > tab1.B then tab1.A else tab1.B end) as B
from TEST tab1 left join TEST tab2 on tab1.B = tab2.A

クエリと同じ結果が得られますが、デカルト結合がないため、はるかに高速です。

于 2012-11-21T16:49:09.850 に答える
0

テストするダービーデータベースはありませんが、これでうまくいくと思います。
a/bとb/aのどちらがバックリンクであるかをどのように判断できるかを指定しなかったため、正しい方向であることがわかった最初のオカレンスを使用しました。

クエリの背後にある考え方は、同じテーブルを結合して、バックリンクと見つかったアイテムの位置を表すrow_numberを取得することです。次に、テーブルをその位置で結合し、最初に出現したテーブルを取得します。

select TOT1.A, TOT2.B
(select distinct t1.A, t1.B, row_number() over() as num
from test t1
join test t2
on t1.A = t2.B and t1.B = t2.A) as TOT1
join
(select distinct t1.A, t1.B, row_number() over() as num
from test t1
join test t2
on t1.A = t2.B and t1.B = t2.A) as TOT2
on TOT1.A = TOT2.B and TOT1.B = TOT2.A and TOT1.NUM < TOT2.NUM
于 2012-11-21T16:27:31.860 に答える
0
SELECT *
FROM ztable t
WHERE EXISTS (
    SELECT * FROM ztable x
    WHERE x.a = t.b AND x.b = t.a
    AND x.a > x.b -- tie breaker
    );

exists には、(相関した) サブクエリが外部のクエリから見えないという利点があります。そのため、select *テーブル t の列のみに展開されます。

于 2012-11-24T16:24:26.600 に答える
0

これまでのすべての回答に感謝します

最初の問題を少し修正した (より簡単な) バージョンがあります。「対応する」行のチェックは必要ありません。後方参照をスキップするだけで済みます。

これまでに fthhiellas ソリューションを変更しました (以下を参照)。どういうわけか、もっと簡単な解決策が必要だと思います。

select distinct
( case when tab1.A < tab1.B then tab1.A else tab1.B end ) as A,
( case when tab1.A > tab1.B then tab1.A else tab1.B end) as B
from TEST tab1, TEST tab2

ダービーにとらわれないので、別のdbシステムに乗り換える際にCASE機能に問題が出ないかなぁ。すべての異なる SQL 方言 (mysql、postgres、oracle、mssql など) で動作する「ユニバーサル」ソリューションが適しています。

何か案は?

于 2012-11-22T11:36:07.580 に答える
0

以下に、挿入されたデータとともにテーブルを作成するためのSQLコードがあります

CREATE TABLE TEST (A varchar(4), B varchar(4));
INSERT INTO TEST (ID,A,B) VALUES ('1','d','a');
INSERT INTO TEST (ID,A,B) VALUES ('1','c','a');
INSERT INTO TEST (ID,A,B) VALUES ('1','b','a');
INSERT INTO TEST (ID,A,B) VALUES ('1','a','xxx');
INSERT INTO TEST (ID,A,B) VALUES ('1','a','d');
INSERT INTO TEST (ID,A,B) VALUES ('1','a','c');
INSERT INTO TEST (ID,A,B) VALUES ('1','a','b');
INSERT INTO TEST (ID,A,B) VALUES ('2','g','a');
INSERT INTO TEST (ID,A,B) VALUES ('2','a','g');
INSERT INTO TEST (ID,A,B) VALUES ('3','f','b');
INSERT INTO TEST (ID,A,B) VALUES ('3','b','f');
INSERT INTO TEST (ID,A,B) VALUES ('4','s','r');
INSERT INTO TEST (ID,A,B) VALUES ('4','r','s');
INSERT INTO TEST (ID,A,B) VALUES ('5','r','t');
INSERT INTO TEST (ID,A,B) VALUES ('7','h','g');

前に説明したように、次のクエリを使用します。

select distinct tab1.ID,
   ( case when tab1.A < tab1.B then tab1.A else tab1.B end ) as A,
   ( case when tab1.A > tab1.B then tab1.A else tab1.B end) as B
from TEST tab1, TEST tab2

...私は望ましい結果を得ました:

ID  A  B
--  -- --
1   a  b
1   a  c
1   a  d
1   a  xxx
2   a  g
3   b  f
4   r  s
5   r  t
7   g  h

申し訳ありませんが、ここで何かを見逃しているかもしれませんが、あなたのソリューションはまだ意図したとおりに機能していないようです。

@fthiella: 私はあなたのソリューションをテストしました:

SELECT tab1.*
FROM TEST tab1 LEFT JOIN TEST tab2 on tab1.B=tab2.A
WHERE tab1.A<tab1.B OR tab2.A is null

結果 (a/b重複、g/h欠落):

ID  A  B
--  -- --
1   a  b
1   a  b
1   a  c
1   a  xxx
2   a  g
3   b  f
4   r  s
5   r  t

@wildplasser: このソリューションも機能しないようです

SELECT * FROM TEST t
WHERE EXISTS (
    SELECT * FROM TEST x
    WHERE x.a = t.b AND x.b = t.a
    AND x.a > x.b -- tie breaker
    );

結果(a/xxxおよびr/t欠落しています):

ID  A  B
--  -- --
1   a  b
1   a  c
1   a  d
2   a  g
3   b  f
4   r  s
于 2012-11-27T10:12:10.380 に答える