sql select查询在同一个表中

时间:2012-11-21 15:21:24

标签: sql select

我有一个与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子句的第二部分无法正常工作。

你有任何提示吗?任何有关这方面的帮助将不胜感激。

问候 彼得

P.S。我正在使用德比数据库。

7 个答案:

答案 0 :(得分:5)

您可以将最后一行更改为:

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

答案 1 :(得分: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

它提供与查询相同的结果,但它更快,因为没有笛卡尔联接。

答案 2 :(得分: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

答案 3 :(得分:0)

感谢到目前为止的所有答案

我的第一个问题略有修改(更容易)版本。 我不需要检查“对应”行,我只需要跳过后面的引用。

我到目前为止修改了fthiellas解决方案(见下文)并且它有效。不知何故,我认为必须有一个更简单的解决方案。

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

因为我不限于德比,我想知道切换到另一个数据库系统时CASE功能是否会出现问题。一个'通用'解决方案会很好用,适用于所有不同的sql方言(mysql,postgres,oracle,mssql等)

任何想法?

答案 4 :(得分: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
    );

存在的优点是(相关的)子查询对外部查询不可见;所以select *将只扩展到表t的列。

答案 5 :(得分: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/xxxr/t丢失):

ID  A  B
--  -- --
1   a  b
1   a  c
1   a  d
2   a  g
3   b  f
4   r  s

答案 6 :(得分:0)

你为什么还需要tab2。 这应该根据您想要的结果起作用。

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;