2012-11-21 13 views
5

मेरे पास एक नया एसक्यूएल संबंधित प्रश्न है।एसक्यूएल उसी तालिका में क्वेरी का चयन करें

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

मैं रिकॉर्ड "समकक्षों" केवल, यानी मैं केवल तभी है तालिका में b aa b प्राप्त करना चाहते हैं, लेकिन मैं के लिए क्वेरी करने के लिए करना चाहते हैं:

चलो कहते हैं कि मैं इस साधारण तालिका डालते हैं "बैक लिंक" को छोड़ना चाहते हैं (जो यहां b a है)। योग करने के लिए मैं निम्नलिखित परिणाम

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

के बाद से मामले 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 क्लॉज का दूसरा भाग वांछित के रूप में काम नहीं करता है।

क्या आपके पास कोई संकेत है? इसके लिए कोई भी सहायता अति सराहनीय होगी।

संबंध पीटर

पी.एस. मैं डर्बी डीबी का उपयोग कर रहा हूँ।

+4

'बी ए'' बी 'का एक बैक लिंक है। लेकिन 'बी' भी 'बी ए 'का एक बैक लिंक है। आप कैसे चुनना चाहते हैं कि कौन सा रखना है और कौन सा छोड़ना है? – fthiella

+0

लेकिन कैसे पता चले कि सही उत्तर क्या है (ऑर्डर)? क्यों नहीं बी और एन एम या बी ए और एन मीटर? – Justin

उत्तर

4

आप करने के लिए अपने अंतिम पंक्ति को बदल सकता है:

AND x1.A < x1.B 

मतलब यह है कि या तो अपने कॉलम कभी नहीं स्वयं संदर्भित कर रहे हैं (उदाहरण के लिए: एक, एक) या आप वृत्तीय संदर्भ प्रकट करने के लिए नहीं करना चाहती है। आप, तो करते हैं:

AND x1.A <= x1.B 

संपादित करें: अब तक

i 'सभी प्रश्नों के उत्तर के लिए

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

मेरे पास परीक्षण करने के लिए डर्बी डीबी नहीं है लेकिन मुझे लगता है कि यह काम करना चाहिए।
जैसा कि आपने यह निर्दिष्ट नहीं किया है कि हम कैसे तय कर सकते हैं कि ए/बी और बी/ए के बीच कौन सा बैक लिंक है, मैंने पहली बार पहली दिशा का सही दिशा पाया।

क्वेरी के पीछे विचार बैक लिंक पाने के लिए एक ही तालिका में शामिल हो रहा है और एक पंक्ति_नंबर पाया गया आइटम की स्थिति का प्रतिनिधित्व करता है। फिर स्थिति के साथ तालिकाओं को एक साथ जोड़ना और पहली घटना के साथ एक को लेना।

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

इससे कोई फ़र्क नहीं पड़ता कि कौन सा पिछला लिंक "ए/बी" या "बी/ए" है। ठीक है, यह एक आत्मा है। आपका समाधान ठीक है, लेकिन यह डीबी सिस्टम स्वतंत्र नहीं है। जैसे mysql row_number() फ़ंक्शन प्रदान नहीं करता है। यद्यपि कामकाज हैं। –

+0

आपने निर्दिष्ट किया है कि आप एक डर्बीडीबी का उपयोग कर रहे हैं, इसलिए मैं डर्बीडीबी कार्यक्षमता –

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

@ पी.पेट धन्यवाद भी काम करता है ... मुझे यह मानना ​​है कि आपका स्वीकृत उत्तर मेरा से अधिक सुरुचिपूर्ण है :) – 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 

के बाद से मैं डर्बी तक ही सीमित नहीं रहा हूँ, मैं आश्चर्य है कि अगर मामला समारोह के साथ एक समस्या हो जाएगा जब एक और डाटाबेस प्रणाली में परिवर्तित हो। एक 'सार्वभौमिक' समाधान अच्छा होगा जो सभी अलग-अलग एसक्यूएल बोलीभाषाओं (mysql, postgres, oracle, mssql, आदि) के साथ काम करता है

कोई विचार?

+0

मेरा अद्यतन उत्तर देखें ... यह आपको एक ही परिणाम देगा लेकिन यह आपकी क्वेरी से बहुत तेज होगा। मामला मानक एसक्यूएल कब होता है इसलिए इसे अधिकांश डीबीएमएस पर काम करना चाहिए। – 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 
    ); 

मौजूद लाभ यह है कि (corellated) सबक्वेरी बाहर क्वेरी को दिखाई नहीं देता है; इसलिए select * केवल तालिका टी के कॉलम तक विस्तारित होगा।

+0

अपेक्षित काम नहीं करता –

0

के रूप में पहले बताया गया है, इस क्वेरी का उपयोग कर नीचे आप डाला डेटा

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 

खेद लोग, शायद मैं यहाँ som याद आती है कुछ लेकिन ऐसा लगता है कि आपके समाधान अभी भी इरादे के रूप में काम नहीं करते हैं।

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

मैंने अपना जवाब फिर से संपादित किया है, यह अब आपकी क्वेरी के समान होना चाहिए, केवल तेज़ है क्योंकि कोई कार्टशियन शामिल नहीं है – fthiella

संबंधित मुद्दे