2012-11-21 61 views
5

我有一個newby sql相關的問題。在同一表中的sql select查詢

比方說,我有這個簡單的表:

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 

因爲在案件b a被處理的a b是從我的結果集中刪除這個sql查詢不起作用。

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子句的第二部分不按要求工作。

你有什麼提示嗎?任何幫助,這將不勝感激。

問候 彼得

附:我正在使用德比分貝。

+4

'b a'是'a b'的反向鏈接。而且'a''是'b a'的後面鏈接。你想如何選擇保留哪一個以及哪一個跳過? – fthiella

+0

但是如何知道什麼是正確答案(訂單)?爲什麼不是b和n m或b a和n m? – Justin

回答

4

則可以將最後一行更改爲:

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 
+0

這是最優雅的解決方案,我猜...和它的作品般的魅力......非常感謝傑森! :) –

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 
+0

無論哪一個是反向鏈接「a/b」或「b/a」都無關緊要。 好吧,它似乎是一個靈魂。你的解決方案沒問題,但它不是數據庫系統獨立的。例如mysql不提供row_number()函數。儘管如此,還是有解決方法。 –

+0

你指定你用的是DerbyDb,所以我使用DerbyDb功能 –

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 

它給出了相同的結果作爲查詢,但它的速度更快,因爲沒有笛卡爾加入。

+0

感謝提供解決方案,該解決方案也工作 –

+0

@ P.Pete謝謝...我不得不承認,你接受的答案比我更優雅:) – fthiella

+0

是它作品和更快沒有WHERE子句... THX –

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的,甲骨文,MSSQL等)

任何想法的作品?

+0

看到我更新的答案...它會給你相同的結果,但它會比你的查詢快得多。情況是什麼時候是標準的SQL,所以它應該適用於大多數DBMS。 – fthiella

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的列。

+0

預期 –

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 
+1

我再次編輯我的答案是不行的,它應該是相同的查詢現在,只有更快,因爲沒有笛卡兒連接 – fthiella