6

我有一个 newby sql 相关的问题。

假设我有这个简单的表:

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

我想查询仅具有“对应项”的记录,即我只想在表中a bb 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 子句的第二部分不能按预期工作。

你有什么提示吗?对此的任何帮助将不胜感激。

问候彼得

ps 我正在使用 derby db。

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

我没有要测试的 derby db,但我认为这应该可以。
由于您没有指定我们如何确定 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

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

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

到目前为止,我修改了 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 等)

有任何想法吗?

于 2012-11-22T11:36:07.580 回答
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 的列。

于 2012-11-24T16:24:26.600 回答
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 回答
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;
于 2021-05-12T23:40:42.530 回答