SQLite

2011-09-12 14 views
5

के भीतर निकटतम डुप्लिकेट पंक्तियों (जैसा कि ग्रुप बाय, हैविंग, COUNT द्वारा निर्धारित किया गया है) से "पहले" (जैसा कि ऑर्डर द्वारा निर्धारित किया गया है) को चुनना मुझे एक समस्या है जो मेरे बाहर थोड़ा सा है (मैं वास्तव में बहुत खुश हूं मैं एक बीटा हूं) डुप्लिकेट (इसलिए GROUP BY, HAVING, COUNT) शामिल है, जो SQLite के साथ आए मानक कार्यों के भीतर समाधान को रखकर मिश्रित है। मैं पाइथन से sqlite3 मॉड्यूल का उपयोग कर रहा हूं।SQLite

उदाहरण तालिका कार्यकर्ताओं, कॉलम:

* ID: integer, auto-incrementing 
* ColA: integer 
* ColB: varchar(20) 
* UserType: varchar(20) 
* LoadMe: Boolean 

(हाँ, SQLite के डेटाटाइप्स नाममात्र कर रहे हैं)

मेरे डेटा तालिका, श्रमिक, शुरू में लगता है कि:

ID ColA ColB UserType LoadMe 
1 1  a  Alpha  0 
2 1  b  Beta  0 
3 2  a  Alpha  0 
4 2  a  Beta  0 
5 2  b  Delta  0 
6 2  b  Alpha  0 
7 1  a  Delta  0 
8 1  b  Epsilon 0 
9 1  c  Gamma  0 
10 4  b  Delta  0 
11 5  a  Alpha  0 
12 5  a  Beta  0 
13 5  b  Gamma  0 
14 5  a  Alpha  0 

मैं चाहूँगा सक्षम करने के लिए, एक नए कारखाने में ट्रकों पर लोड होने के लिए, सभी श्रमिक जिनके पास कोला और कोल्ब के बीच अद्वितीय संयोजन हैं। उन डुप्लीकेट्स (जुड़वां, तिहराई, आदि, शायद बोकानोव्स्की की प्रक्रिया के माध्यम से) जहां कोला और कोल्ब के अद्वितीय संयोजनों में एक से अधिक कार्यकर्ता हैं, मैं डुप्लिकेट के प्रत्येक सेट से केवल एक को चुनना चाहता हूं। समस्या को कठिन बनाने के लिए, मैं अतिरिक्त रूप से ORDER BY के किसी रूप में उपयोगकर्ता टाइप के आधार पर डुप्लीकेट के प्रत्येक सेट से चयन करने में सक्षम होना चाहता हूं। मैं एक डरावनी चतुर समस्या, या ORDER BY UserType DESC पर काम करने के लिए "अल्फा" के उपयोगकर्ता टाइप के साथ पहला "डुप्लिकेट" चुनना चाहता हूं, ताकि मैं सबसे कम श्रमिकों के लिए ब्लैक ट्यूनिक्स के लिए ऑर्डर जारी कर सकूं।

आप देख सकते हैं कि आईडी 9, 10, और 13 में कोला और कोल्ब के अद्वितीय संयोजन हैं और सबसे आसानी से पहचाने जाते हैं। 1-ए, 1-बी, 2-ए, 2-बी, और 5-संयोजन, हालांकि, उनके भीतर डुप्लिकेट हैं।

मेरे वर्तमान प्रक्रिया है, यह अब तक खड़ा के रूप में:

0) प्रत्येक व्यक्ति को एक अद्वितीय ID संख्या के साथ आता है। यह जन्म पर किया जाता है।

1) SET सभी श्रमिक LoadMe को = 1.

UPDATE Workers 
SET LoadMe = 1 

2) दो कॉलम (ग्रुप द्वारा कोला, ColB) में उनकी समानता के आधार पर मेरे डुप्लीकेट खोजें:

SELECT Wk1.* 
FROM Workers AS Wk1 
INNER JOIN (
    SELECT ColA, ColB 
    FROM Workers 
    GROUP BY ColA, ColB 
    HAVING COUNT(*) > 1 
) AS Wk2 
ON Wk1.ColA = Wk2.ColA 
AND Wk1.ColB = Wk2.ColB 
ORDER BY ColA, ColB 

3) मेरीमें डुप्लिकेट के प्रत्येक सेट के लिए LoadMe = 0.

UPDATE Workers 
SET LoadMe = 0 
WHERE ID IN (
    SELECT Wk1.ID 
    FROM Workers AS Wk1 
    INNER JOIN (
     SELECT ColA, ColB 
     FROM Workers 
     GROUP BY ColA, ColB 
     HAVING COUNT(*) > 1 
    ) AS Wk2 
    ON Wk1.ColA = Wk2.ColA 
    AND Wk1.ColB = Wk2.ColB 
) 

4) करने के लिए अपने सभी प्रतिलिपियों SET, ORDER एड BY UserType, SELECT केवल एक, सूची में पहले, करने के लिए 1.

LoadMe SET के लिए इस तालिका में दिखाई देगा:

ID ColA ColB UserType LoadMe 
1 1  a  Alpha  1 
2 1  b  Beta  1 
3 2  a  Alpha  1 
4 2  a  Beta  0 
5 2  b  Delta  0 
6 2  b  Alpha  1 
7 1  a  Delta  0 
8 1  b  Epsilon 0 
9 1  c  Gamma  1 
10 4  b  Delta  1 
11 5  a  Alpha  1 
12 5  a  Beta  0 
13 5  b  Gamma  1 
14 5  a  Alpha  0 

ORDER एड BY कोला, ColB, प्रयोक्ता प्रकार है, तो आईडी, और हो सकता है GROUP BY स्तंभों के आधार पर विभाजित, (और अंत में स्पष्टता के लिए स्थान दिया गया है) कि एक ही डेटा की तरह लग रहे:

ID ColA ColB UserType LoadMe 
1 1  a  Alpha  1 
7 1  a  Delta  0 

2 1  b  Beta  1 
8 1  b  Epsilon 0 

9 1  c  Gamma  1 

3 2  a  Alpha  1 
4 2  a  Beta  0 

6 2  b  Alpha  1 
5 2  b  Delta  0 

10 4  b  Delta  1 

11 5  a  Alpha  1 
14 5  a  Alpha  0 
12 5  a  Beta  0 

13 5  b  Gamma  1 

मैं कर रहा हूँ आखिरी कदम पर उलझन में और एक ईपीएसलॉन-माइनस सेमी-मॉरॉन की तरह महसूस करते हैं।मैं पहले डेटाबेस स्थान से डुप्लिकेट को प्रोग्राम स्पेस में खींच रहा था और पाइथन के भीतर काम कर रहा था, लेकिन यह स्थिति बार-बार नहीं होती है और मैं इसे और अधिक स्थायी रूप से हल करना चाहता हूं।

उत्तर

1

मुझे इस तरह की समस्या को तोड़ना पसंद है।

SELECT ColA,ColB FROM Workers GROUP BY ColA,ColB 
अब इन जोड़ों आप उच्चतम प्राथमिकता वाले रिकॉर्ड लगाना चाहते से प्रत्येक के लिए

: पहला कदम अद्वितीय कोला, ColB जोड़े की पहचान है। एक में शामिल होने के काम नहीं करेगा क्योंकि आप प्रत्येक अद्वितीय जोड़ी के लिए कई रिकॉर्ड के साथ खत्म हो जाएगा लेकिन एक सबक्वेरी काम करेगा:

SELECT ColA,ColB, 
    (SELECT id FROM Workers w1 
    WHERE w1.ColA=w2.ColA AND w1.ColB=w2.ColB 
    ORDER BY UserType LIMIT 1) AS id 
FROM Workers w2 GROUP BY ColA,ColB; 

आप सबक्वेरी प्राथमिकता को नियंत्रित करने में ORDER BY खंड बदल सकते हैं। LIMIT 1 यह सुनिश्चित करता है कि प्रत्येक सबक्वायरी के लिए केवल एक रिकॉर्ड है (अन्यथा sqlite WHERE खंड से मेल खाने वाले अंतिम रिकॉर्ड को वापस कर देगा, हालांकि मुझे यकीन नहीं है कि इसकी गारंटी है)।

इस क्वेरी का परिणाम ColA, ColB, id के साथ लोड होने वाले रिकॉर्ड की एक सूची है। मैं शायद कि से सीधे काम करेगा और LoadMe से छुटकारा पाने, लेकिन आप ऐसा कर सकता है आप इसे रखना चाहते हैं:

BEGIN TRANSACTION; 
UPDATE Workers SET LoadMe=0; 
UPDATE Workers SET LoadMe=1 
WHERE id IN (SELECT 
    (SELECT id FROM Workers w1 
    WHERE w1.ColA=w2.ColA AND w1.ColB=w2.ColB 
    ORDER BY UserType LIMIT 1) AS id 
    FROM Workers w2 GROUP BY ColA,ColB); 
COMMIT; 

LoadMe ध्वज को साफ करता है और फिर रिकॉर्ड द्वारा लौटाए से प्रत्येक के लिए 1 के लिए यह सेट कि हमारे अंतिम प्रश्न लेनदेन गारंटी देता है कि यह सब एक कदम के रूप में होता है या विफल रहता है और कभी भी एक असंगत स्थिति में LoadMe फ़ील्ड नहीं छोड़ता है।