मानों के एक सेट से, मैं उन मानों को कैसे ढूँढ सकता हूं जो किसी तालिका के कॉलम में संग्रहीत नहीं हैं?


12

मेरे पास एक टेबल है जो संभावित रूप से सैकड़ों हजारों पूर्णांक स्टोर करेगा

desc id_key_table;

+----------------+--------------+------+-----+---------+-------+
| Field          | Type         | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+-------+
| id_key         | int(16)      | NO   | PRI | NULL    |       |
+----------------+--------------+------+-----+---------+-------+

एक कार्यक्रम से, मेरे पास पूर्णांकों का एक बड़ा सेट है। मैं यह देखना चाहता हूं कि इनमें से कौन-सा पूर्णांक उपरोक्त id_key कॉलम में नहीं हैं।

अब तक मैं निम्नलिखित दृष्टिकोणों के साथ आया हूँ:

1) प्रत्येक पूर्णांक के माध्यम से Iterate करें और एक प्रदर्शन करें:

select count(*) count from id_key_table where id_key = :id_key

जब गिनती 0 है तो id_key तालिका से गायब है।

यह ऐसा करने के लिए एक भयानक, भयानक तरीका लगता है।


2) एक अस्थायी तालिका बनाएं, प्रत्येक मान को अस्थायी तालिका में डालें, और दो तालिकाओं पर एक JOIN करें।

create temporary table id_key_table_temp (id_key int(16) primary key );

insert into id_key_table_temp values (1),(2),(3),...,(500),(501);

select temp.id_key
from id_key_table_temp temp left join id_key_table as main 
         on temp.id_key = main.id_key 
where main.killID is null;

drop table id_key_table_temp;

यह सबसे अच्छा दृष्टिकोण की तरह लगता है, हालांकि, मुझे यकीन है कि एक बेहतर दृष्टिकोण है जो मैंने अभी तक नहीं सोचा है। मैं एक अस्थायी तालिका नहीं बनाना चाहता हूं और यह निर्धारित करने के लिए एक क्वेरी का उपयोग करना चाहता हूं कि कौन से पूर्णांक गायब हैं।

क्या इस प्रकार की खोज के लिए एक उचित क्वेरी है?

(माई एसक्यूएल)


2
मुझे पसंद है कि आपने अपना प्रश्न कैसे किया (DBA में आपका स्वागत है), हालांकि, यह स्टैकओवरफ्लो पर कहीं अधिक उपयुक्त है क्योंकि यह किसी प्रकार के प्रोग्राम के साथ बातचीत करने से संबंधित है (डीबीए प्रति सेबा नहीं)
डेरेक डाउनी

स्वागत के लिए धन्यवाद, मैंने सोचा कि इस तरह की जगह में स्टैकओवरफ्लो की तुलना में कुछ अधिक गुरु हो सकते हैं। हालांकि वहां फिर से पूछने में मुझे कोई आपत्ति नहीं है।
क्लिंटन

2
जैसा कि सुझाव दिया गया है, मैंने स्टैकऑवरफ्लो को रीपोस्ट किया: stackoverflow.com/questions/5967822/…
क्लिंटन

इस प्रश्न में एसक्यूएल सर्वर के लिए इसी तरह की स्थिति का इलाज किया गया था: संग्रहीत डेटा में बहुत सारे डेटा भेजने के लिए तकनीक । आपको यह पता लगाना चाहिए कि समस्या अन्य डीबी वातावरण में समान है। वैसे भी, मैं समाधान सं। 2 - आईडी, पार्स की सूची भेजें, तालिका में रखें, अपनी मुख्य तालिका में शामिल हों। यदि आप अन्य समाधानों का उपयोग नहीं कर सकते हैं, लेकिन यहां आपको :-) खोदना होगा।
मैरियन

जवाबों:


7

आपका दूसरा समाधान बाएँ जोइन का उपयोग करके अब तक का सबसे अच्छा तरीका है। मैं एक अस्थायी तालिका का उपयोग नहीं करता, मैं एक नियमित तालिका का उपयोग करता हूं और किसी भी समय नए मान के साथ इसे आबाद करता हूं जब भी आप क्वेरी चलाना चाहते थे।


5

ऐसा लगता है कि "पूर्णांकों का बड़ा सेट" अभी भी "हजारों हजारों पूर्णांक" के साथ तालिका से काफी छोटा है। उस दमन के साथ और जब तक कि MySQL में आपके पूर्णांक की सारणी का उपयोग करने का एक तरीका आपके SQL कथन में नहीं है, आपका दूसरा विकल्प संभवतः सबसे अच्छा है। यह मुख्य टेबल पर अस्थायी तालिका और सूचकांक का एक पूर्ण स्कैन करना चाहिए। प्राथमिक लाभ यह है कि इसे केवल एक बार में सैकड़ों हजारों पूर्णांकों वाले सूचकांक को स्कैन करना होता है और केवल क्लाइंट को परिणाम भेजना होता है। आपकी क्वेरी निम्नलिखित के रूप में फिर से लिखी जा सकती है (लेकिन आवश्यकता नहीं है):

SELECT * FROM id_key_table_temp 
WHERE id_key NOT IN (select id_key FROM id_key_table);

मैं एक नियमित टेबल पर एक अस्थायी तालिका का समर्थन नहीं कर रहा हूं क्योंकि मुझे MySQL प्लेटफॉर्म पर अंतर का कोई ज्ञान नहीं है। ओरेकल में एक अस्थायी तालिका शायद सबसे अच्छी होगी, लेकिन फिर ओरेकल में आप सिर्फ एक सारणी को तालिका के रूप में उपयोग करेंगे और सीधे इसमें शामिल होंगे।
लेह रिफ़ेल

3

एक अस्थायी तालिका के साथ और डालने के बजाय insert into id_key_table_temp values (1),(2),(3),...,(500),(501);, आप उन सभी मूल्यों के साथ एक उप-निर्माण का निर्माण कर सकते हैं जिन्हें आप जाँचने का प्रयास कर रहे हैं:

select id_key
from ( select @row := @row + 1 as id_key 
       from (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s1,
            (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s2,
            (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s3,
            (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s4,
            (select @row:=0) s5 ) s
where id_key in(1, 2, 3, 500, 501)
      and id_key not in (select id_key from main);

2

जैसा कि मेरी टिप्पणी में उल्लेख किया गया है, यह स्टैकओवरफ्लो के लिए संभवतः अधिक अनुकूल है। हालांकि, मुझे लगता है कि उन दोनों समाधान सबसे अच्छा नहीं हैं:

समाधान 1 के लिए कई चयन कॉल की आवश्यकता होती है, बहुत अक्षम

समाधान 2 बेहतर है, लेकिन मुझे यकीन नहीं है कि कई मूल्य सर्वोत्तम समाधान डालने की लागत है।

एक संभावित समाधान 3 को एक प्रश्न बनाना होगा:

SELECT DISTINCT id_key FROM id_key_table

और क्रमिक रूप से अपने पूर्णांक सेट से अंतर प्राप्त करें और डीबी में क्या है। सबसे कम, (चूंकि यह बहुत पूर्णांक है) यह मार्ग समाधान 1 से बेहतर होना चाहिए। समाधान 2 में बहुत सारे पूर्णांकों को वापस करने की क्षमता है (यदि तालिका में एक गुच्छा है जो आपके डेटासेट में नहीं है), तो यह ™ निर्भर करता है!


मैं इस समाधान का प्रशंसक नहीं हूं क्योंकि परिणाम बहुत बड़ा होगा।
क्लिंटन

@ क्लिंटन सच है, लेकिन यह आपके दूसरे समाधान में भी बहुत बड़ा हो सकता है, अगर आप इसे फ़िल्टर करने के लिए पर्याप्त पूर्णांक प्रदान नहीं करते हैं।
डेरेक डाउनी

2

मैं बहुत StackOverflow में इसे संबोधित किया है , लेकिन मैं स्थायी अस्थायी (PermTemp) तालिका का उपयोग करने पर अधिक विस्तृत करना चाहूंगा। ( स्थायी अस्थायी, यह एक ऑक्सीमोरन नहीं है ?)

में StackOverflow , मैं संग्रहीत प्रक्रिया test.CreateSampleTable और test.GetMissingIntegers एक नमूना तालिका बनाने और उसके बाद बड़ा कर मतभेदों को खोजने के लिए शामिल हों पहले पॉप्युलेट करना एक गतिशील अस्थायी तालिका बनाने के लिए किया था।

इस बार, आइए सैंपल टेबल को स्थायी टेबल टेबल के साथ बनाएं।

यहाँ परीक्षण है।

DELIMITER $$

DROP PROCEDURE IF EXISTS `LoadSampleTables` $$
CREATE DEFINER=`lwdba`@`127.0.0.1` PROCEDURE `LoadSampleTables`(maxinttoload INT)
BEGIN

  DECLARE X,OKTOUSE,MAXLOOP INT;

  DROP TABLE IF EXISTS test.id_key_table;
  DROP TABLE IF EXISTS test.id_key_table_keys;
  CREATE TABLE test.id_key_table (id_key INT(16)) ENGINE=MyISAM;
  CREATE TABLE test.id_key_table_keys (id_key INT(16)) ENGINE=MyISAM;

  SET X=1;
  WHILE X <= maxinttoload DO
    INSERT INTO test.id_key_table VALUES (X);
    SET X = X + 1;
  END WHILE;
  ALTER TABLE test.id_key_table ADD PRIMARY KEY (id_key);

  SET MAXLOOP = FLOOR(SQRT(maxinttoload));
  SET X = 2;
  WHILE X <= MAXLOOP DO
    DELETE FROM test.id_key_table WHERE MOD(id_key,X) = 0 AND id_key > X;
    SELECT MIN(id_key) INTO OKTOUSE FROM test.id_key_table WHERE id_key > X;
    SET X = OKTOUSE;
  END WHILE;
  OPTIMIZE TABLE test.id_key_table;

  INSERT INTO test.id_key_table_keys SELECT id_key FROM test.id_key_table;
  ALTER TABLE test.id_key_table_keys ADD PRIMARY KEY (id_key);
  OPTIMIZE TABLE test.id_key_table_keys;

END $$

DELIMITER ;

इसे चलाने के बाद, यहाँ सारणी और उनकी सामग्री दी गई है:

mysql> call test.loadsampletables(25);
+-------------------+----------+----------+----------+
| Table             | Op       | Msg_type | Msg_text |
+-------------------+----------+----------+----------+
| test.id_key_table | optimize | status   | OK       |
+-------------------+----------+----------+----------+
1 row in set (0.20 sec)

+------------------------+----------+----------+----------+
| Table                  | Op       | Msg_type | Msg_text |
+------------------------+----------+----------+----------+
| test.id_key_table_keys | optimize | status   | OK       |
+------------------------+----------+----------+----------+
1 row in set (0.28 sec)

Query OK, 0 rows affected (0.29 sec)

mysql> select * from test.id_key_table;
+--------+
| id_key |
+--------+
|      1 |
|      2 |
|      3 |
|      5 |
|      7 |
|     11 |
|     13 |
|     17 |
|     19 |
|     23 |
+--------+
10 rows in set (0.00 sec)

mysql> select * from test.id_key_table_keys;
+--------+
| id_key |
+--------+
|      1 |
|      2 |
|      3 |
|      5 |
|      7 |
|     11 |
|     13 |
|     17 |
|     19 |
|     23 |
+--------+
10 rows in set (0.00 sec)

यहाँ PermTemp तालिका के लिए ट्रिगर हैं

mysql> DELIMITER $$
mysql>
mysql> CREATE TRIGGER test.AddPermTempKey AFTER INSERT ON test.id_key_table
    -> FOR EACH ROW
    -> BEGIN
    ->     INSERT IGNORE INTO test.id_key_table_keys VALUES (NEW.id_key);
    -> END $$
Query OK, 0 rows affected (0.09 sec)

mysql>
mysql> CREATE TRIGGER test.DeletePermTempKey AFTER DELETE ON test.id_key_table
    -> FOR EACH ROW
    -> BEGIN
    ->     DELETE FROM test.id_key_table_keys WHERE id_key = OLD.id_key;
    -> END $$
Query OK, 0 rows affected (0.08 sec)

mysql>
mysql> DELIMITER ;

अब, अभिलेखों के एक नए बैच को आयात करने की अनुमति देता है, टेबल टेस्ट ।weekly_batch, पहले इस्तेमाल की गई कुछ चाबियां, अन्य कुंजी ब्रांड स्पेलिंग:

mysql> CREATE TABLE test.weekly_batch (id_key INT(16)) ENGINE=MyISAM;
Query OK, 0 rows affected (0.04 sec)

mysql> INSERT INTO test.weekly_batch VALUES (17),(19),(23),(29),(31),(37),(41);
Query OK, 7 rows affected (0.00 sec)
Records: 7  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE test.weekly_batch ADD PRIMARY KEY (id_key);
Query OK, 7 rows affected (0.08 sec)
Records: 7  Duplicates: 0  Warnings: 0

आइए test.weekly_batch लेते हैं और इसे सुरक्षित रूप से test.id_key_table_keys में मर्ज करते हैं और टेबल टेस्ट बनाते हैं। new_keys_to_load:

DELIMITER $$

DROP PROCEDURE IF EXISTS `test`.`ImportWeeklyBatch` $$
CREATE PROCEDURE `test`.`ImportWeeklyBatch` ()
TheStoredProcedure:BEGIN

  DECLARE RCOUNT INT;

  SELECT COUNT(1) INTO RCOUNT FROM information_schema.tables
  WHERE table_schema='test' AND table_name='weekly_batch';
  IF RCOUNT = 0 THEN
    LEAVE TheStoredProcedure;
  END IF;
  SELECT COUNT(1) INTO RCOUNT FROM test.weekly_batch;
  IF RCOUNT = 0 THEN
    LEAVE TheStoredProcedure;
  END IF;
  DROP TABLE IF EXISTS test.new_keys_to_load;
  CREATE TABLE test.new_keys_to_load (id_key INT(16));
  INSERT INTO test.new_keys_to_load (id_key)
  SELECT id_key FROM test.weekly_batch A
  LEFT JOIN test.id_key_table_keys B USING (id_key)
  WHERE B.id_key IS NULL;

  SELECT * FROM test.new_keys_to_load;

END $$

DELIMITER ;

यहाँ परिणाम है:

mysql> call test.importweeklybatch;
+--------+
| id_key |
+--------+
|     29 |
|     31 |
|     37 |
|     41 |
+--------+
4 rows in set (0.14 sec)

इस बिंदु से, आयात करने के लिए नई कुंजियों की ब्रांडिंग की सूची के रूप में new_keys_to_load तालिका का उपयोग करें। चूंकि new_keys_to_load PermTemp तालिका से छोटा है, इसलिए आपको हमेशा बाईं ओर के बाईं ओर new_keys_to_load का उपयोग करना चाहिए।


मैंने इसका उत्तर SO पर पहले ही दे दिया था
RolandoMySQLDBA
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.