我有一个与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。我正在使用德比数据库。
答案 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/xxx
和r/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;