SQL क्वेरी कई तालिकाओं से डेटा लौटाती है


434

मैं निम्नलिखित जानना चाहूंगा:

  • मेरे डेटाबेस में कई तालिकाओं से डेटा कैसे प्राप्त करें?
  • ऐसा करने के लिए कौन से तरीके हैं?
  • जोड़ और यूनियन क्या हैं और वे एक दूसरे से कैसे भिन्न हैं?
  • मुझे दूसरों की तुलना में प्रत्येक का उपयोग कब करना चाहिए?

मैं अपने (उदाहरण के लिए - PHP) अनुप्रयोग में इसका उपयोग करने की योजना बना रहा हूं, लेकिन डेटाबेस के खिलाफ कई क्वेरी नहीं चलाना चाहता, मुझे एक ही क्वेरी में कई टेबल से डेटा प्राप्त करने के लिए क्या विकल्प हैं?

नोट: मैं इसे लिख रहा हूं क्योंकि मैं कई प्रश्नों पर एक अच्छी तरह से लिखित गाइड से लिंक करने में सक्षम होना चाहता हूं जो कि मैं लगातार पीएचपी कतार में आता हूं, इसलिए जब मैं कोई उत्तर देता हूं तो मैं इसे और अधिक विस्तार से लिंक कर सकता हूं।

उत्तर निम्नलिखित को कवर करते हैं:

  1. भाग 1 - सम्मिलित और संघ
  2. भाग 2 - उपश्रेणियाँ
  3. भाग 3 - ट्रिक्स और कुशल कोड
  4. भाग 4 - खंड से उपश्रेणियाँ
  5. भाग 5 - जॉन की चाल के मिश्रित बैग

जवाबों:


469

भाग 1 - सम्मिलित और संघ

इस उत्तर को शामिल किया गया:

  1. भाग 1
  2. भाग 2
    • उपश्रेणियाँ - वे क्या हैं, उनका उपयोग कहाँ किया जा सकता है और क्या देखना है
    • कार्टेशियन AKA से जुड़ता है - ओह, दुख!

एक डेटाबेस में कई तालिकाओं से डेटा पुनर्प्राप्त करने के कई तरीके हैं। इस उत्तर में, मैं ANSI-92 सिंटैक्स में शामिल होऊंगा। यह कई अन्य ट्यूटोरियल्स के लिए भिन्न हो सकता है जो पुराने ANSI-89 सिंटैक्स का उपयोग करते हैं (और यदि आप 89 के लिए उपयोग किए जाते हैं, तो बहुत कम सहज ज्ञान युक्त लग सकता है - लेकिन मैं कह सकता हूं कि यह कोशिश करना है) क्योंकि यह बहुत आसान है समझने के लिए जब प्रश्न अधिक जटिल होने लगते हैं। इसका उपयोग क्यों करें? क्या कोई प्रदर्शन लाभ है? संक्षिप्त उत्तर नहीं है, लेकिन यह है एक बार आप इसकी आदत हो पढ़ने में आसान। इस सिंटैक्स का उपयोग करके अन्य लोगों द्वारा लिखे गए प्रश्नों को पढ़ना आसान है।

मैं एक छोटे साइरड की अवधारणा का भी उपयोग करने जा रहा हूं, जिसमें एक डेटाबेस है कि वह किन कारों को उपलब्ध कराएगी। मालिक ने आपको अपने आईटी कंप्यूटर आदमी के रूप में काम पर रखा है और आपसे उम्मीद करता है कि आप उसे उस डेटा को छोड़ने में सक्षम होंगे जो वह टोपी के ड्रॉप पर पूछता है।

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

पहली तालिका केवल एक रंग लिस्टिंग है ताकि हम जान सकें कि कार यार्ड में हमारे पास कौन से रंग हैं।

mysql> create table colors(id int(3) not null auto_increment primary key, 
    -> color varchar(15), paint varchar(10));
Query OK, 0 rows affected (0.01 sec)

mysql> show columns from colors;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(3)      | NO   | PRI | NULL    | auto_increment |
| color | varchar(15) | YES  |     | NULL    |                |
| paint | varchar(10) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)

mysql> insert into colors (color, paint) values ('Red', 'Metallic'), 
    -> ('Green', 'Gloss'), ('Blue', 'Metallic'), 
    -> ('White' 'Gloss'), ('Black' 'Gloss');
Query OK, 5 rows affected (0.00 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> select * from colors;
+----+-------+----------+
| id | color | paint    |
+----+-------+----------+
|  1 | Red   | Metallic |
|  2 | Green | Gloss    |
|  3 | Blue  | Metallic |
|  4 | White | Gloss    |
|  5 | Black | Gloss    |
+----+-------+----------+
5 rows in set (0.00 sec)

ब्रांडों की तालिका अलग-अलग ब्रांडों की कारों की पहचान करती है जो कि शायद बाहर बेच सकती हैं।

mysql> create table brands (id int(3) not null auto_increment primary key, 
    -> brand varchar(15));
Query OK, 0 rows affected (0.01 sec)

mysql> show columns from brands;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(3)      | NO   | PRI | NULL    | auto_increment |
| brand | varchar(15) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)

mysql> insert into brands (brand) values ('Ford'), ('Toyota'), 
    -> ('Nissan'), ('Smart'), ('BMW');
Query OK, 5 rows affected (0.00 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> select * from brands;
+----+--------+
| id | brand  |
+----+--------+
|  1 | Ford   |
|  2 | Toyota |
|  3 | Nissan |
|  4 | Smart  |
|  5 | BMW    |
+----+--------+
5 rows in set (0.00 sec)

मॉडल तालिका विभिन्न प्रकार की कारों को कवर करेगी, इसके लिए वास्तविक कार मॉडल के बजाय विभिन्न कार प्रकारों का उपयोग करना सरल होगा।

mysql> create table models (id int(3) not null auto_increment primary key, 
    -> model varchar(15));
Query OK, 0 rows affected (0.01 sec)

mysql> show columns from models;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(3)      | NO   | PRI | NULL    | auto_increment |
| model | varchar(15) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql> insert into models (model) values ('Sports'), ('Sedan'), ('4WD'), ('Luxury');
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> select * from models;
+----+--------+
| id | model  |
+----+--------+
|  1 | Sports |
|  2 | Sedan  |
|  3 | 4WD    |
|  4 | Luxury |
+----+--------+
4 rows in set (0.00 sec)

और अंत में, इन सभी अन्य तालिकाओं को टाई करने के लिए, तालिका जो सब कुछ एक साथ बाँधती है। आईडी फ़ील्ड वास्तव में कारों की पहचान करने के लिए इस्तेमाल किया जाने वाला अद्वितीय लॉट नंबर है।

mysql> create table cars (id int(3) not null auto_increment primary key, 
    -> color int(3), brand int(3), model int(3));
Query OK, 0 rows affected (0.01 sec)

mysql> show columns from cars;
+-------+--------+------+-----+---------+----------------+
| Field | Type   | Null | Key | Default | Extra          |
+-------+--------+------+-----+---------+----------------+
| id    | int(3) | NO   | PRI | NULL    | auto_increment |
| color | int(3) | YES  |     | NULL    |                |
| brand | int(3) | YES  |     | NULL    |                |
| model | int(3) | YES  |     | NULL    |                |
+-------+--------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

mysql> insert into cars (color, brand, model) values (1,2,1), (3,1,2), (5,3,1), 
    -> (4,4,2), (2,2,3), (3,5,4), (4,1,3), (2,2,1), (5,2,3), (4,5,1);
Query OK, 10 rows affected (0.00 sec)
Records: 10  Duplicates: 0  Warnings: 0

mysql> select * from cars;
+----+-------+-------+-------+
| id | color | brand | model |
+----+-------+-------+-------+
|  1 |     1 |     2 |     1 |
|  2 |     3 |     1 |     2 |
|  3 |     5 |     3 |     1 |
|  4 |     4 |     4 |     2 |
|  5 |     2 |     2 |     3 |
|  6 |     3 |     5 |     4 |
|  7 |     4 |     1 |     3 |
|  8 |     2 |     2 |     1 |
|  9 |     5 |     2 |     3 |
| 10 |     4 |     5 |     1 |
+----+-------+-------+-------+
10 rows in set (0.00 sec)

इससे हमें विभिन्न प्रकार के जुड़नों के नीचे के उदाहरणों को कवर करने के लिए पर्याप्त डेटा (मुझे आशा है) मिलेगा और उन्हें सार्थक बनाने के लिए पर्याप्त डेटा भी देगा।

इसलिए इसकी चपेट में आकर , बॉस के पास सभी स्पोर्ट्स कारों की आईडी जानना चाहता है

यह एक साधारण दो टेबल जॉइन है। हमारे पास एक तालिका है जो मॉडल और तालिका में उपलब्ध स्टॉक के साथ की पहचान करती है। जैसा कि आप देख सकते हैं, तालिका के modelस्तंभ का डेटा हमारे पास मौजूद तालिका carsके modelsस्तंभ से संबंधित carsहै। अब, हम जानते हैं कि मॉडल तालिका में एक आईडी है 1, Sportsजिससे जुड़ने के लिए लिख सकते हैं।

select
    ID,
    model
from
    cars
        join models
            on model=ID

तो यह प्रश्न सही लगता है? हमने दो तालिकाओं की पहचान की है और हमारे पास आवश्यक जानकारी का उपयोग करते हैं और एक ऐसे जुड़ाव का उपयोग करते हैं जो सही ढंग से पहचानता है कि किस स्तंभ को शामिल होना है।

ERROR 1052 (23000): Column 'ID' in field list is ambiguous

अरे नहीं! हमारी पहली क्वेरी में एक त्रुटि! हाँ, और यह एक बेर है। आप देखते हैं, क्वेरी को वास्तव में सही कॉलम मिला है, लेकिन उनमें से कुछ दोनों तालिकाओं में मौजूद हैं, इसलिए डेटाबेस भ्रमित हो जाता है कि हम वास्तविक कॉलम का क्या मतलब है और कहां हैं। इसके समाधान के लिए दो उपाय हैं। पहला अच्छा और सरल है, हम tableName.columnNameडेटाबेस का उपयोग वास्तव में हमारे कहने का उपयोग कर सकते हैं , जैसे:

select
    cars.ID,
    models.model
from
    cars
        join models
            on cars.model=models.ID

+----+--------+
| ID | model  |
+----+--------+
|  1 | Sports |
|  3 | Sports |
|  8 | Sports |
| 10 | Sports |
|  2 | Sedan  |
|  4 | Sedan  |
|  5 | 4WD    |
|  7 | 4WD    |
|  9 | 4WD    |
|  6 | Luxury |
+----+--------+
10 rows in set (0.00 sec)

दूसरे को शायद अधिक बार उपयोग किया जाता है और इसे टेबल अलियासिंग कहा जाता है। इस उदाहरण में तालिकाओं में अच्छे और छोटे सरल नाम हैं, लेकिन कुछ टाइप करने से KPI_DAILY_SALES_BY_DEPARTMENTशायद जल्दी पुराना हो जाएगा, इसलिए एक सरल तरीका इस तरह तालिका को उपनाम देना है:

select
    a.ID,
    b.model
from
    cars a
        join models b
            on a.model=b.ID

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

स्पष्ट रूप से, हमें अपनी क्वेरी में एक क्लॉज़ जोड़ने की आवश्यकता है। हम स्पोर्ट्स कारों की पहचान ID=1या तो कर सकते हैं model='Sports'। जैसा कि आईडी अनुक्रमित है और प्राथमिक कुंजी (और यह कम टाइपिंग होती है), हमारी क्वेरी में इसका उपयोग करने देती है।

select
    a.ID,
    b.model
from
    cars a
        join models b
            on a.model=b.ID
where
    b.ID=1

+----+--------+
| ID | model  |
+----+--------+
|  1 | Sports |
|  3 | Sports |
|  8 | Sports |
| 10 | Sports |
+----+--------+
4 rows in set (0.00 sec)

बिंगो! बॉस खुश है। बेशक, एक मालिक होने के नाते और उसने जो भी मांगा उससे खुश नहीं, वह जानकारी देखता है, फिर कहता है मुझे भी रंग चाहिए

ठीक है, इसलिए हमारे पास पहले से लिखित हमारी क्वेरी का एक अच्छा हिस्सा है, लेकिन हमें एक तीसरी तालिका का उपयोग करने की आवश्यकता है जो कि रंग है। अब, हमारी मुख्य सूचना तालिका carsकार रंग आईडी को संग्रहीत करती है और यह वापस रंग आईडी कॉलम से जुड़ती है। तो, मूल के समान तरीके से, हम एक तीसरी तालिका में शामिल हो सकते हैं:

select
    a.ID,
    b.model
from
    cars a
        join models b
            on a.model=b.ID
        join colors c
            on a.color=c.ID
where
    b.ID=1

+----+--------+
| ID | model  |
+----+--------+
|  1 | Sports |
|  3 | Sports |
|  8 | Sports |
| 10 | Sports |
+----+--------+
4 rows in set (0.00 sec)

लानत, यद्यपि तालिका सही ढंग से शामिल हो गई थी और संबंधित कॉलम जुड़े हुए थे, हम उस नई तालिका से वास्तविक जानकारी में खींचना भूल गए जिसे हमने जोड़ा था।

select
    a.ID,
    b.model,
    c.color
from
    cars a
        join models b
            on a.model=b.ID
        join colors c
            on a.color=c.ID
where
    b.ID=1

+----+--------+-------+
| ID | model  | color |
+----+--------+-------+
|  1 | Sports | Red   |
|  8 | Sports | Green |
| 10 | Sports | White |
|  3 | Sports | Black |
+----+--------+-------+
4 rows in set (0.00 sec)

ठीक है, कि एक पल के लिए हमारी पीठ पीछे बॉस है। अब, इसके बारे में कुछ और विस्तार से बताने के लिए। जैसा कि आप देख सकते हैं, fromहमारे बयान में खंड हमारी मुख्य तालिका को जोड़ता है (मैं अक्सर एक तालिका का उपयोग करता हूं जिसमें लुकअप या आयाम तालिका के बजाय जानकारी होती है। क्वेरी बस के रूप में अच्छी तरह से चारों ओर स्विच टेबल के साथ काम करेगी, लेकिन जब कम समझ में आता है। हम कुछ महीनों के समय में इसे पढ़ने के लिए इस क्वेरी पर वापस आते हैं, इसलिए अक्सर एक क्वेरी लिखने की कोशिश करना सबसे अच्छा होता है जो समझने में आसान और आसान होगा - इसे सहज रूप से बाहर रखें, अच्छी इंडेंटिंग का उपयोग करें ताकि सब कुछ जितना स्पष्ट हो सके यह हो सकता है। यदि आप दूसरों को सिखाने के लिए जाते हैं, तो इन विशेषताओं को उनके प्रश्नों में डालने की कोशिश करें - खासकर यदि आप उन्हें समस्या निवारण करेंगे।

इस तरीके से अधिक से अधिक तालिकाओं को जोड़ना पूरी तरह से संभव है।

select
    a.ID,
    b.model,
    c.color
from
    cars a
        join models b
            on a.model=b.ID
        join colors c
            on a.color=c.ID
        join brands d
            on a.brand=d.ID
where
    b.ID=1

जबकि मैं एक तालिका को शामिल करना भूल गया, जहाँ हम joinकथन में एक से अधिक कॉलम में शामिल होना चाहते हैं , यहाँ एक उदाहरण है। यदि modelsतालिका में ब्रांड-विशिष्ट मॉडल होते थे और इसलिए एक स्तंभ भी होता था , जिसे फ़ील्ड पर brandवापस brandsतालिका से जोड़ा जाता है ID, तो इसे निम्न प्रकार से किया जा सकता है:

select
    a.ID,
    b.model,
    c.color
from
    cars a
        join models b
            on a.model=b.ID
        join colors c
            on a.color=c.ID
        join brands d
            on a.brand=d.ID
            and b.brand=d.ID
where
    b.ID=1

आप देख सकते हैं, ऊपर दी गई क्वेरी न केवल ज्वाइन की गई टेबलों को मेन टेबल से जोड़ती है cars, बल्कि पहले से ही शामिल टेबलों के बीच जॉइन को भी निर्दिष्ट करती है। यदि ऐसा नहीं किया गया था, तो परिणाम को कार्टेशियन जॉइन कहा जाता है - जो कि डीबीए खराब के लिए बोलता है। एक कार्टेज़ियन जॉइन वह होता है जहाँ पंक्तियों को लौटाया जाता है क्योंकि जानकारी डेटाबेस को यह नहीं बताती है कि परिणामों को कैसे सीमित किया जाए, इसलिए क्वेरी उन सभी पंक्तियों को लौटाती है जो मापदंड को फिट करती हैं।

इसलिए, एक कार्टेशियन में शामिल होने का एक उदाहरण देने के लिए, निम्नलिखित प्रश्न को चलाने दें:

select
    a.ID,
    b.model
from
    cars a
        join models b

+----+--------+
| ID | model  |
+----+--------+
|  1 | Sports |
|  1 | Sedan  |
|  1 | 4WD    |
|  1 | Luxury |
|  2 | Sports |
|  2 | Sedan  |
|  2 | 4WD    |
|  2 | Luxury |
|  3 | Sports |
|  3 | Sedan  |
|  3 | 4WD    |
|  3 | Luxury |
|  4 | Sports |
|  4 | Sedan  |
|  4 | 4WD    |
|  4 | Luxury |
|  5 | Sports |
|  5 | Sedan  |
|  5 | 4WD    |
|  5 | Luxury |
|  6 | Sports |
|  6 | Sedan  |
|  6 | 4WD    |
|  6 | Luxury |
|  7 | Sports |
|  7 | Sedan  |
|  7 | 4WD    |
|  7 | Luxury |
|  8 | Sports |
|  8 | Sedan  |
|  8 | 4WD    |
|  8 | Luxury |
|  9 | Sports |
|  9 | Sedan  |
|  9 | 4WD    |
|  9 | Luxury |
| 10 | Sports |
| 10 | Sedan  |
| 10 | 4WD    |
| 10 | Luxury |
+----+--------+
40 rows in set (0.00 sec)

अच्छा भगवान, यह बदसूरत है। हालाँकि, जहाँ तक डेटाबेस का सवाल है, यह वही है जो पूछा गया था। क्वेरी में, हम के लिए के लिए कहा IDसे carsऔर modelसे models। साथ ही, हम निर्दिष्ट नहीं किया है कैसे तालिकाओं में शामिल होने, डेटाबेस से मेल खाता है कि हर पहली तालिका से पंक्ति के साथ हर दूसरी तालिका से पंक्ति।

ठीक है, इसलिए बॉस वापस आ गया है, और वह फिर से अधिक जानकारी चाहता है। मुझे वही सूची चाहिए, लेकिन इसमें 4WD भी शामिल हैं

हालांकि, यह हमें इसे पूरा करने के दो अलग-अलग तरीकों को देखने के लिए एक महान बहाना देता है। हम इस तरह से एक और शर्त जोड़ सकते हैं:

select
    a.ID,
    b.model,
    c.color
from
    cars a
        join models b
            on a.model=b.ID
        join colors c
            on a.color=c.ID
        join brands d
            on a.brand=d.ID
where
    b.ID=1
    or b.ID=3

जबकि ऊपर पूरी तरह से अच्छी तरह से काम करेगा, चलो इसे अलग तरीके से देखते हैं, यह एक शानदार बहाना है कि यह कैसे unionकाम करेगा।

हम जानते हैं कि निम्नलिखित सभी स्पोर्ट्स कारें वापस आएँगी:

select
    a.ID,
    b.model,
    c.color
from
    cars a
        join models b
            on a.model=b.ID
        join colors c
            on a.color=c.ID
        join brands d
            on a.brand=d.ID
where
    b.ID=1

और निम्नलिखित सभी 4WDs लौटाएगा:

select
    a.ID,
    b.model,
    c.color
from
    cars a
        join models b
            on a.model=b.ID
        join colors c
            on a.color=c.ID
        join brands d
            on a.brand=d.ID
where
    b.ID=3

इसलिए union allउनके बीच एक खंड जोड़कर , दूसरी क्वेरी के परिणामों को पहले क्वेरी के परिणामों से जोड़ दिया जाएगा।

select
    a.ID,
    b.model,
    c.color
from
    cars a
        join models b
            on a.model=b.ID
        join colors c
            on a.color=c.ID
        join brands d
            on a.brand=d.ID
where
    b.ID=1
union all
select
    a.ID,
    b.model,
    c.color
from
    cars a
        join models b
            on a.model=b.ID
        join colors c
            on a.color=c.ID
        join brands d
            on a.brand=d.ID
where
    b.ID=3

+----+--------+-------+
| ID | model  | color |
+----+--------+-------+
|  1 | Sports | Red   |
|  8 | Sports | Green |
| 10 | Sports | White |
|  3 | Sports | Black |
|  5 | 4WD    | Green |
|  7 | 4WD    | White |
|  9 | 4WD    | Black |
+----+--------+-------+
7 rows in set (0.00 sec)

जैसा कि आप देख सकते हैं, पहले क्वेरी के परिणाम पहले लौटाए जाते हैं, उसके बाद दूसरे क्वेरी के परिणाम।

इस उदाहरण में, यह निश्चित रूप से पहली क्वेरी का उपयोग करने के लिए बहुत आसान होगा, लेकिन unionविशिष्ट मामलों के लिए प्रश्न महान हो सकते हैं। वे तालिकाओं से तालिकाओं से विशिष्ट परिणाम वापस करने का एक शानदार तरीका है जो आसानी से एक साथ शामिल नहीं होते हैं - या उस मामले के लिए पूरी तरह से असंबंधित तालिकाओं के लिए। हालांकि पालन करने के लिए कुछ नियम हैं।

  • पहली क्वेरी से स्तंभ प्रकार नीचे दिए गए प्रत्येक क्वेरी से स्तंभ प्रकार से मेल खाना चाहिए।
  • परिणामों के पूरे सेट की पहचान करने के लिए पहली क्वेरी से कॉलम के नाम का उपयोग किया जाएगा।
  • प्रत्येक क्वेरी में कॉलम की संख्या समान होनी चाहिए।

अब, आप सोच रहे होंगे कि उपयोग करने में क्या अंतर है unionऔर union all। एक unionक्वेरी डुप्लिकेट हटा देगा, जबकि एक union allनहीं होगा। इसका मतलब यह है कि unionओवर का उपयोग करते समय एक छोटा प्रदर्शन होता है, union allलेकिन परिणाम इसके लायक हो सकते हैं - मैं इस तरह की चीज पर अटकल नहीं लगाऊंगा।

इस नोट पर, यहां कुछ अतिरिक्त नोटों को ध्यान देने योग्य हो सकता है।

  • यदि हम परिणाम का आदेश देना चाहते हैं, तो हम उपयोग कर सकते हैं, order byलेकिन आप अब और उपनाम का उपयोग नहीं कर सकते। उपरोक्त क्वेरी में, किसी order by a.IDको जोड़ने से एक त्रुटि होगी - जहां तक ​​परिणाम का संबंध है, कॉलम को IDइसके बजाय कहा जाता है a.ID- भले ही दोनों प्रश्नों में समान उपनाम का उपयोग किया गया हो।
  • हमारे पास केवल एक order byबयान हो सकता है, और यह अंतिम कथन के रूप में होना चाहिए।

अगले उदाहरणों के लिए, हम अपनी तालिकाओं में कुछ अतिरिक्त पंक्तियों को जोड़ रहे हैं।

मैंने Holdenब्रांडों की तालिका में जोड़ा है। मैंने इसमें एक पंक्ति भी जोड़ी carsहै जिसका colorमूल्य है 12- जिसका रंग तालिका में कोई संदर्भ नहीं है।

ठीक है, बॉस फिर से वापस आ गया है, बाहर अनुरोधों को भौंकते हुए - * मुझे प्रत्येक ब्रांड की एक गिनती चाहिए जो हम ले जाते हैं और उसमें कारों की संख्या! ' ।

राइट्यो, इसलिए पहली चीज जो हमें करने की आवश्यकता है वह है संभावित ब्रांडों की पूरी सूची।

select
    a.brand
from
    brands a

+--------+
| brand  |
+--------+
| Ford   |
| Toyota |
| Nissan |
| Smart  |
| BMW    |
| Holden |
+--------+
6 rows in set (0.00 sec)

अब, जब हम इसे अपनी कार तालिका में शामिल करते हैं, तो हमें निम्नलिखित परिणाम मिलते हैं:

select
    a.brand
from
    brands a
        join cars b
            on a.ID=b.brand
group by
    a.brand

+--------+
| brand  |
+--------+
| BMW    |
| Ford   |
| Nissan |
| Smart  |
| Toyota |
+--------+
5 rows in set (0.00 sec)

जो निश्चित रूप से एक समस्या है - हम उस प्यारे Holdenब्रांड का कोई उल्लेख नहीं देख रहे हैं जो मैंने जोड़ा है।

ऐसा इसलिए है क्योंकि दोनों तालिकाओं में मेल खाने वाली पंक्तियों के लिए एक जुड़ाव दिखता है । जैसा कि कारों में कोई डेटा नहीं होता है जो कि प्रकार का Holdenहोता है, इसे वापस नहीं किया जाता है। यह वह जगह है जहाँ हम एक outerजॉइन का उपयोग कर सकते हैं । यह एक तालिका से सभी परिणाम लौटाएगा कि क्या वे दूसरी तालिका में मेल खाते हैं या नहीं:

select
    a.brand
from
    brands a
        left outer join cars b
            on a.ID=b.brand
group by
    a.brand

+--------+
| brand  |
+--------+
| BMW    |
| Ford   |
| Holden |
| Nissan |
| Smart  |
| Toyota |
+--------+
6 rows in set (0.00 sec)

अब जब हमारे पास ऐसा है, तो हम एक गिनती प्राप्त करने के लिए एक प्यारा समुच्चय फ़ंक्शन जोड़ सकते हैं और एक पल के लिए बॉस को वापस पा सकते हैं।

select
    a.brand,
    count(b.id) as countOfBrand
from
    brands a
        left outer join cars b
            on a.ID=b.brand
group by
    a.brand

+--------+--------------+
| brand  | countOfBrand |
+--------+--------------+
| BMW    |            2 |
| Ford   |            2 |
| Holden |            0 |
| Nissan |            1 |
| Smart  |            1 |
| Toyota |            5 |
+--------+--------------+
6 rows in set (0.00 sec)

और उस के साथ, बॉस की खोपड़ी को दूर।

अब, इसे कुछ और विस्तार से समझाने के लिए, बाहरी जोड़ leftया rightप्रकार के हो सकते हैं । लेफ्ट या राईट परिभाषित करता है कि कौन सी तालिका पूरी तरह से शामिल है। ए left outer joinमें बाईं ओर तालिका से सभी पंक्तियां शामिल होंगी, जबकि (आपने यह अनुमान लगाया था) right outer joinतालिका के सभी परिणामों को दाईं ओर परिणामों में लाता है।

कुछ डेटाबेस दोनों तालिकाओं full outer joinसे परिणाम (जो मिलान या नहीं) वापस लाएंगे , लेकिन यह सभी डेटाबेस में समर्थित नहीं है।

अब, मैं शायद इस बिंदु पर समय में आंकड़ा कर रहा हूं, आप सोच रहे हैं कि क्या आप किसी प्रकार के क्वेरी में विलय कर सकते हैं या नहीं - और जवाब हां है, आप बिल्कुल कर सकते हैं।

select
    b.brand,
    c.color,
    count(a.id) as countOfBrand
from
    cars a
        right outer join brands b
            on b.ID=a.brand
        join colors c
            on a.color=c.ID
group by
    a.brand,
    c.color

+--------+-------+--------------+
| brand  | color | countOfBrand |
+--------+-------+--------------+
| Ford   | Blue  |            1 |
| Ford   | White |            1 |
| Toyota | Black |            1 |
| Toyota | Green |            2 |
| Toyota | Red   |            1 |
| Nissan | Black |            1 |
| Smart  | White |            1 |
| BMW    | Blue  |            1 |
| BMW    | White |            1 |
+--------+-------+--------------+
9 rows in set (0.00 sec)

तो, ऐसा क्यों नहीं है जो अपेक्षित परिणाम थे? ऐसा इसलिए है क्योंकि हमने कारों से ब्रांडों में बाहरी जुड़ाव का चयन किया है, लेकिन रंगों में शामिल होने के लिए इसे निर्दिष्ट नहीं किया गया था - इसलिए कि विशेष रूप से जुड़ने से दोनों तालिकाओं में मैच के परिणाम वापस आ जाएंगे।

यहां वह क्वेरी है जो अपेक्षित परिणाम प्राप्त करने के लिए काम करेगी:

select
    a.brand,
    c.color,
    count(b.id) as countOfBrand
from
    brands a
        left outer join cars b
            on a.ID=b.brand
        left outer join colors c
            on b.color=c.ID
group by
    a.brand,
    c.color

+--------+-------+--------------+
| brand  | color | countOfBrand |
+--------+-------+--------------+
| BMW    | Blue  |            1 |
| BMW    | White |            1 |
| Ford   | Blue  |            1 |
| Ford   | White |            1 |
| Holden | NULL  |            0 |
| Nissan | Black |            1 |
| Smart  | White |            1 |
| Toyota | NULL  |            1 |
| Toyota | Black |            1 |
| Toyota | Green |            2 |
| Toyota | Red   |            1 |
+--------+-------+--------------+
11 rows in set (0.00 sec)

जैसा कि हम देख सकते हैं, हमारे पास क्वेरी में दो बाहरी जोड़ हैं और परिणाम उम्मीद के मुताबिक आ रहे हैं।

अब, उन अन्य प्रकार के जोड़ों के बारे में आप कैसे पूछते हैं? अंतर के बारे में क्या?

ठीक है, सभी डेटाबेस समर्थन नहीं करते हैं, intersectionलेकिन बहुत अधिक सभी डेटाबेस आपको एक सम्मिलित (या एक अच्छी तरह से संरचित जहां कथन कम से कम) के माध्यम से एक चौराहे बनाने की अनुमति देगा।

एक आंतरिकता unionऊपर वर्णित के अनुसार कुछ प्रकार से जुड़ने का एक प्रकार है - लेकिन अंतर यह है कि यह केवल डेटा की पंक्तियाँ देता है जो संघ द्वारा शामिल किए गए विभिन्न व्यक्तिगत प्रश्नों के बीच समान हैं (और मेरा मतलब समान है)। केवल वही पंक्तियाँ जो हर संबंध में समान हैं, उन्हें वापस कर दिया जाएगा।

एक सरल उदाहरण इस प्रकार होगा:

select
    *
from
    colors
where
    ID>2
intersect
select
    *
from
    colors
where
    id<4

जबकि एक सामान्य unionक्वेरी तालिका की सभी पंक्तियों को वापस कर देगी (पहली क्वेरी जो कुछ भी लौटाती है ID>2और दूसरी कुछ भी हो ID<4) जिसके परिणामस्वरूप एक पूर्ण सेट होगा, एक प्रतिच्छेद क्वेरी केवल पंक्ति मिलान id=3को लौटाएगी क्योंकि यह दोनों मानदंडों को पूरा करती है।

अब, यदि आपका डेटाबेस किसी intersectक्वेरी का समर्थन नहीं करता है , तो उपरोक्त को निम्नलिखित क्वेरी के साथ आसानी से शामिल किया जा सकता है:

select
    a.ID,
    a.color,
    a.paint
from
    colors a
        join colors b
            on a.ID=b.ID
where
    a.ID>2
    and b.ID<4

+----+-------+----------+
| ID | color | paint    |
+----+-------+----------+
|  3 | Blue  | Metallic |
+----+-------+----------+
1 row in set (0.00 sec)

यदि आप एक डेटाबेस का उपयोग करके दो अलग-अलग तालिकाओं में एक चौराहे का प्रदर्शन करना चाहते हैं जो अंतःक्रियात्मक क्वेरी का समर्थन नहीं करता है, तो आपको तालिकाओं के प्रत्येक स्तंभ पर एक जुड़ाव बनाने की आवश्यकता होगी ।


2
@Fluffeh अच्छा जवाब। मेरा एक सुझाव है: यदि आप इसे हत्यारा SQL ट्यूटोरियल बनाना चाहते हैं, तो आप केवल वेन आरेख जोड़ने के लिए गायब हैं; मैं समझ गया कि दायें बायें और दायें उनके धन्यवाद से जुड़ते हैं। व्यक्तिगत अनुरोध: क्या आपके पास सामान्य गलतियों / प्रदर्शन ट्यूनिंग पर कोई ट्यूटोरियल है?
स्ट्रायचाइल्ड 01

25
अरे मेरा। मेरा स्क्रॉल व्हील टूट गया है। बढ़िया सवाल और जवाब। काश मैं इस 10 बार उत्थान कर पाता।
अमल मुरली

3
हेह, सकारात्मक प्रतिक्रिया के लिए धन्यवाद। हालांकि स्क्रॉल करते रहें, यह केवल पहला उत्तर था। एसओ ने कहा कि मेरा उत्तर एक "उत्तर" में फिट होने के लिए बहुत लंबा था इसलिए मुझे कुछ का उपयोग करना पड़ा :)
फ़ुलफे

7
ईमानदारी से, मुझे लगता है कि इस उत्तर को कुछ हद तक छोटा किया जाना चाहिए।
einpoklum 17

बहुत बढ़िया लेख। डेटाबेस में शामिल होने के लिए 101.
maqs

101

ठीक है, मुझे यह पोस्ट बहुत रोचक लगी और मैं अपना कुछ ज्ञान क्वेरी बनाने के लिए साझा करना चाहूंगा। इस Fluffeh के लिए धन्यवाद । अन्य जो इसे पढ़ सकते हैं और महसूस कर सकते हैं कि मैं गलत हूं, मेरे उत्तर को संपादित करने और आलोचना करने के लिए 101% मुफ़्त हैं। ( ईमानदारी से, मैं अपनी गलती को सुधारने के लिए बहुत आभारी महसूस करता हूं। )

मैं MySQLटैग में अक्सर पूछे जाने वाले प्रश्नों में से कुछ पोस्ट कर रहा हूँ ।


ट्रिक नंबर 1 ( कई स्थितियों से मेल खाती पंक्तियाँ )

इस स्कीमा को दिया

CREATE TABLE MovieList
(
    ID INT,
    MovieName VARCHAR(25),
    CONSTRAINT ml_pk PRIMARY KEY (ID),
    CONSTRAINT ml_uq UNIQUE (MovieName)
);

INSERT INTO MovieList VALUES (1, 'American Pie');
INSERT INTO MovieList VALUES (2, 'The Notebook');
INSERT INTO MovieList VALUES (3, 'Discovery Channel: Africa');
INSERT INTO MovieList VALUES (4, 'Mr. Bean');
INSERT INTO MovieList VALUES (5, 'Expendables 2');

CREATE TABLE CategoryList
(
    MovieID INT,
    CategoryName VARCHAR(25),
    CONSTRAINT cl_uq UNIQUE(MovieID, CategoryName),
    CONSTRAINT cl_fk FOREIGN KEY (MovieID) REFERENCES MovieList(ID)
);

INSERT INTO CategoryList VALUES (1, 'Comedy');
INSERT INTO CategoryList VALUES (1, 'Romance');
INSERT INTO CategoryList VALUES (2, 'Romance');
INSERT INTO CategoryList VALUES (2, 'Drama');
INSERT INTO CategoryList VALUES (3, 'Documentary');
INSERT INTO CategoryList VALUES (4, 'Comedy');
INSERT INTO CategoryList VALUES (5, 'Comedy');
INSERT INTO CategoryList VALUES (5, 'Action');

सवाल

सभी फिल्में खोजें जो कम से कम दोनों श्रेणियों Comedyऔर Romanceश्रेणियों से संबंधित हों ।

समाधान

यह सवाल कभी-कभी बहुत पेचीदा हो सकता है। ऐसा लग सकता है कि इस तरह एक प्रश्न का उत्तर होगा: -

SELECT  DISTINCT a.MovieName
FROM    MovieList a
        INNER JOIN CategoryList b
            ON a.ID = b.MovieID
WHERE   b.CategoryName = 'Comedy' AND
        b.CategoryName = 'Romance'

SQLFiddle डेमो

जो निश्चित रूप से बहुत गलत है क्योंकि यह कोई परिणाम नहीं पैदा करता है । इसका स्पष्टीकरण यह है कि प्रत्येक पंक्तिCategoryName पर केवल एक मान्य मूल्य है । उदाहरण के लिए, पहली शर्त सही है , दूसरी स्थिति हमेशा झूठी होती है। इस प्रकार, ऑपरेटर का उपयोग करके , दोनों शर्त सही होनी चाहिए; अन्यथा, यह गलत होगा। एक अन्य प्रश्न इस प्रकार है,AND

SELECT  DISTINCT a.MovieName
FROM    MovieList a
        INNER JOIN CategoryList b
            ON a.ID = b.MovieID
WHERE   b.CategoryName IN ('Comedy','Romance')

SQLFiddle डेमो

और परिणाम अभी भी गलत है क्योंकि यह रिकॉर्ड करने के लिए मेल खाता है जिसमें कम से कम एक मैच है categoryNameवास्तविक समाधान फिल्म प्रति रिकॉर्ड उदाहरणों की संख्या की गणना होगी । उदाहरण की संख्या हालत में आपूर्ति किए गए मूल्यों की कुल संख्या से मेल खाना चाहिए।

SELECT  a.MovieName
FROM    MovieList a
        INNER JOIN CategoryList b
            ON a.ID = b.MovieID
WHERE   b.CategoryName IN ('Comedy','Romance')
GROUP BY a.MovieName
HAVING COUNT(*) = 2

SQLFiddle डेमो (जवाब)


ट्रिक नंबर 2 ( प्रत्येक प्रविष्टि के लिए अधिकतम रिकॉर्ड )

स्कीमा दिया,

CREATE TABLE Software
(
    ID INT,
    SoftwareName VARCHAR(25),
    Descriptions VARCHAR(150),
    CONSTRAINT sw_pk PRIMARY KEY (ID),
    CONSTRAINT sw_uq UNIQUE (SoftwareName)  
);

INSERT INTO Software VALUES (1,'PaintMe','used for photo editing');
INSERT INTO Software VALUES (2,'World Map','contains map of different places of the world');
INSERT INTO Software VALUES (3,'Dictionary','contains description, synonym, antonym of the words');

CREATE TABLE VersionList
(
    SoftwareID INT,
    VersionNo INT,
    DateReleased DATE,
    CONSTRAINT sw_uq UNIQUE (SoftwareID, VersionNo),
    CONSTRAINT sw_fk FOREIGN KEY (SOftwareID) REFERENCES Software(ID)
);

INSERT INTO VersionList VALUES (3, 2, '2009-12-01');
INSERT INTO VersionList VALUES (3, 1, '2009-11-01');
INSERT INTO VersionList VALUES (3, 3, '2010-01-01');
INSERT INTO VersionList VALUES (2, 2, '2010-12-01');
INSERT INTO VersionList VALUES (2, 1, '2009-12-01');
INSERT INTO VersionList VALUES (1, 3, '2011-12-01');
INSERT INTO VersionList VALUES (1, 2, '2010-12-01');
INSERT INTO VersionList VALUES (1, 1, '2009-12-01');
INSERT INTO VersionList VALUES (1, 4, '2012-12-01');

सवाल

प्रत्येक सॉफ्टवेयर पर नवीनतम संस्करण का पता लगाएं। निम्नलिखित कॉलम दिखाएं: SoftwareName, Descriptions, LatestVersion( VersionNo स्तंभ से ),DateReleased

समाधान

कुछ SQL डेवलपर्स गलती से MAX()कुल फ़ंक्शन का उपयोग करते हैं। वे इस तरह का निर्माण करते हैं,

SELECT  a.SoftwareName, a.Descriptions,
        MAX(b.VersionNo) AS LatestVersion, b.DateReleased
FROM    Software a
        INNER JOIN VersionList b
            ON a.ID = b.SoftwareID
GROUP BY a.ID
ORDER BY a.ID

SQLFiddle डेमो

( अधिकांश RDBMS इस पर एक सिंटैक्स त्रुटि उत्पन्न करता है क्योंकि group byक्लॉज पर कुछ गैर-एकत्रित स्तंभों को निर्दिष्ट नहीं करने के कारण ) परिणाम LatestVersionप्रत्येक सॉफ़्टवेयर पर सही पैदा करता है लेकिन स्पष्ट रूप से DateReleasedगलत हैं। MySQLसमर्थन नहीं करता है Window Functionsऔर Common Table Expressionअभी तक कुछ RDBMS पहले से ही करते हैं। इस समस्या पर वर्कअराउंड बनाना है subqueryजो versionNoप्रत्येक सॉफ्टवेयर पर व्यक्ति को अधिकतम मिलता है और बाद में अन्य टेबलों पर जुड़ जाता है।

SELECT  a.SoftwareName, a.Descriptions,
        b.LatestVersion, c.DateReleased
FROM    Software a
        INNER JOIN
        (
            SELECT  SoftwareID, MAX(VersionNO) LatestVersion
            FROM    VersionList
            GROUP BY SoftwareID
        ) b ON a.ID = b.SoftwareID
        INNER JOIN VersionList c
            ON  c.SoftwareID = b.SoftwareID AND
                c.VersionNO = b.LatestVersion
GROUP BY a.ID
ORDER BY a.ID

SQLFiddle डेमो (जवाब)


तो वह यह था। जैसे ही मुझे टैग पर कोई अन्य FAQ याद आता है, मैं दूसरी पोस्ट करूँगा MySQLइस छोटे से लेख को पढ़ने के लिए धन्यवाद। मुझे आशा है कि आप कम से कम इस से थोड़ा भी ज्ञान प्राप्त करेंगे।

अद्यतन १


ट्रिक नंबर 3 ( दो आईडी के बीच नवीनतम रिकॉर्ड ढूँढना )

स्कीम्स दी

CREATE TABLE userList
(
    ID INT,
    NAME VARCHAR(20),
    CONSTRAINT us_pk PRIMARY KEY (ID),
    CONSTRAINT us_uq UNIQUE (NAME)  
);

INSERT INTO userList VALUES (1, 'Fluffeh');
INSERT INTO userList VALUES (2, 'John Woo');
INSERT INTO userList VALUES (3, 'hims056');

CREATE TABLE CONVERSATION
(
    ID INT,
    FROM_ID INT,
    TO_ID INT,
    MESSAGE VARCHAR(250),
    DeliveryDate DATE
);

INSERT INTO CONVERSATION VALUES (1, 1, 2, 'hi john', '2012-01-01');
INSERT INTO CONVERSATION VALUES (2, 2, 1, 'hello fluff', '2012-01-02');
INSERT INTO CONVERSATION VALUES (3, 1, 3, 'hey hims', '2012-01-03');
INSERT INTO CONVERSATION VALUES (4, 1, 3, 'please reply', '2012-01-04');
INSERT INTO CONVERSATION VALUES (5, 3, 1, 'how are you?', '2012-01-05');
INSERT INTO CONVERSATION VALUES (6, 3, 2, 'sample message!', '2012-01-05');

सवाल

दो उपयोगकर्ताओं के बीच नवीनतम बातचीत का पता लगाएं।

समाधान

SELECT    b.Name SenderName,
          c.Name RecipientName,
          a.Message,
          a.DeliveryDate
FROM      Conversation a
          INNER JOIN userList b
            ON a.From_ID = b.ID
          INNER JOIN userList c
            ON a.To_ID = c.ID
WHERE     (LEAST(a.FROM_ID, a.TO_ID), GREATEST(a.FROM_ID, a.TO_ID), DeliveryDate)
IN
(
    SELECT  LEAST(FROM_ID, TO_ID) minFROM,
            GREATEST(FROM_ID, TO_ID) maxTo,
            MAX(DeliveryDate) maxDate
    FROM    Conversation
    GROUP BY minFROM, maxTo
)

SQLFiddle डेमो


बहुत बढ़िया! एक चेतावनी जॉन, आपका पहला समाधान केवल इसलिए काम करता है क्योंकि दो क्षेत्रों पर एक अद्वितीय बाधा है। आप एक आम समस्या के साथ मदद के लिए अधिक सामान्य समाधान का उपयोग कर सकते थे। मेरी राय में एकमात्र समाधान के लिए व्यक्तिगत चयन करने के लिए है comedyऔर romanceHavingफिर सूट नहीं करता है ..
nawfal

@nawfal वास्तव में नहीं है, यदि अद्वितीय बाधा नहीं जोड़ी गई थी, तो आपको distinctक्लॉज SQLFiddle डेमो : D
John Woo

63

भाग 2 - उपश्रेणियाँ

ठीक है, अब बॉस फिर से फट गया है - मुझे ब्रांड के साथ हमारी सभी कारों की सूची चाहिए और कुल कितने ब्रांड हैं!

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

हमारे अनुरोध के लिए, पहले एक सरल क्वेरी को एक साथ रखना चाहिए जो प्रत्येक कार और ब्रांड को सूचीबद्ध करेगी:

select
    a.ID,
    b.brand
from
    cars a
        join brands b
            on a.brand=b.ID

अब, यदि हम ब्रांड द्वारा क्रमबद्ध कारों की एक गिनती प्राप्त करना चाहते हैं, तो हम इसे लिख सकते हैं:

select
    b.brand,
    count(a.ID) as countCars
from
    cars a
        join brands b
            on a.brand=b.ID
group by
    b.brand

+--------+-----------+
| brand  | countCars |
+--------+-----------+
| BMW    |         2 |
| Ford   |         2 |
| Nissan |         1 |
| Smart  |         1 |
| Toyota |         5 |
+--------+-----------+

इसलिए, हमें अपनी मूल क्वेरी के लिए गिनती फ़ंक्शन में सीधे जोड़ने में सक्षम होना चाहिए?

select
    a.ID,
    b.brand,
    count(a.ID) as countCars
from
    cars a
        join brands b
            on a.brand=b.ID
group by
    a.ID,
    b.brand

+----+--------+-----------+
| ID | brand  | countCars |
+----+--------+-----------+
|  1 | Toyota |         1 |
|  2 | Ford   |         1 |
|  3 | Nissan |         1 |
|  4 | Smart  |         1 |
|  5 | Toyota |         1 |
|  6 | BMW    |         1 |
|  7 | Ford   |         1 |
|  8 | Toyota |         1 |
|  9 | Toyota |         1 |
| 10 | BMW    |         1 |
| 11 | Toyota |         1 |
+----+--------+-----------+
11 rows in set (0.00 sec)

अफसोस की बात है, नहीं, हम ऐसा नहीं कर सकते। कारण यह है कि जब हम कार आईडी (कॉलम a.ID) में जोड़ते हैं, तो हमें इसे समूह में जोड़ना होता है - इसलिए अब, जब गणना कार्य कार्य करता है, तो प्रति आईडी केवल एक आईडी मिलान होती है।

यह वह जगह है जहां हम हालांकि एक उप-वर्ग का उपयोग कर सकते हैं - वास्तव में हम दो पूरी तरह से अलग-अलग प्रकार के उपकुंजी कर सकते हैं जो उसी परिणाम को वापस कर देंगे जो हमें इसके लिए आवश्यक है। पहला selectउपखंड को बस उपवाक्य में रखना है । इसका मतलब है कि हर बार जब हम डेटा की एक पंक्ति प्राप्त करते हैं, तो सबकुछ बंद हो जाएगा, डेटा का एक कॉलम मिलेगा और फिर इसे हमारे डेटा की पंक्ति में पॉप किया जाएगा।

select
    a.ID,
    b.brand,
    (
    select
        count(c.ID)
    from
        cars c
    where
        a.brand=c.brand
    ) as countCars
from
    cars a
        join brands b
            on a.brand=b.ID

+----+--------+-----------+
| ID | brand  | countCars |
+----+--------+-----------+
|  2 | Ford   |         2 |
|  7 | Ford   |         2 |
|  1 | Toyota |         5 |
|  5 | Toyota |         5 |
|  8 | Toyota |         5 |
|  9 | Toyota |         5 |
| 11 | Toyota |         5 |
|  3 | Nissan |         1 |
|  4 | Smart  |         1 |
|  6 | BMW    |         2 |
| 10 | BMW    |         2 |
+----+--------+-----------+
11 rows in set (0.00 sec)

और बाम!, यह हम करेंगे। यदि आपने देखा है, तो इस उप क्वेरी को हमारे द्वारा लौटाई जाने वाली प्रत्येक डेटा की प्रत्येक पंक्ति के लिए चलना होगा। यहां तक ​​कि इस छोटे से उदाहरण में, हमारे पास केवल पांच अलग-अलग ब्रांड की कार हैं, लेकिन उप-वर्ग ने ग्यारह बार भाग लिया क्योंकि हमारे पास डेटा की ग्यारह पंक्तियां हैं जो हम लौट रहे हैं। तो, इस मामले में, यह कोड लिखने के सबसे कुशल तरीके की तरह नहीं लगता है।

एक अलग दृष्टिकोण के लिए, एक उपकुंजी चलाने और यह दिखावा है कि यह एक तालिका है:

select
    a.ID,
    b.brand,
    d.countCars
from
    cars a
        join brands b
            on a.brand=b.ID
        join
            (
            select
                c.brand,
                count(c.ID) as countCars
            from
                cars c
            group by
                c.brand
            ) d
            on a.brand=d.brand

+----+--------+-----------+
| ID | brand  | countCars |
+----+--------+-----------+
|  1 | Toyota |         5 |
|  2 | Ford   |         2 |
|  3 | Nissan |         1 |
|  4 | Smart  |         1 |
|  5 | Toyota |         5 |
|  6 | BMW    |         2 |
|  7 | Ford   |         2 |
|  8 | Toyota |         5 |
|  9 | Toyota |         5 |
| 10 | BMW    |         2 |
| 11 | Toyota |         5 |
+----+--------+-----------+
11 rows in set (0.00 sec)

ठीक है, इसलिए हमारे पास एक ही परिणाम है (थोड़ा अलग आदेश दिया गया है - ऐसा लगता है कि डेटाबेस इस बार हमने पहले कॉलम द्वारा आदेशित परिणामों को वापस करना चाहता था) - लेकिन वही सही संख्या।

तो, दोनों के बीच क्या अंतर है - और हमें प्रत्येक प्रकार की उपश्रेणी का उपयोग कब करना चाहिए? सबसे पहले, हमें यह सुनिश्चित करने की अनुमति देता है कि हम यह कैसे समझें कि दूसरा काम कैसे करता है। हमने fromअपनी क्वेरी के खंड में दो तालिकाओं का चयन किया , और फिर एक क्वेरी लिखी और डेटाबेस को बताया कि यह वास्तव में एक तालिका थी जिसके बजाय - डेटाबेस पूरी तरह से खुश है। वहाँ कर सकते हैं इस पद्धति का उपयोग करने के लिए कुछ लाभ (और साथ ही कुछ सीमाएं) हो। सबसे महत्वपूर्ण यह है कि यह उपनगर एक बार चला । यदि हमारे डेटाबेस में बड़ी मात्रा में डेटा होता है, तो पहले तरीके से बड़े पैमाने पर सुधार हो सकता है। हालांकि, जैसा कि हम इसे एक तालिका के रूप में उपयोग कर रहे हैं, हमें डेटा की अतिरिक्त पंक्तियों में लाना होगा - ताकि वे वास्तव में डेटा की हमारी पंक्तियों में वापस शामिल हो सकें। हमें यह भी सुनिश्चित करना होगा कि पर्याप्त हैंयदि हम ऊपर क्वेरी में एक साधारण जॉइन का उपयोग करने जा रहे हैं तो डेटा की पंक्तियाँ। यदि आप याद करते हैं, तो जॉइन केवल उन पंक्तियों को वापस खींच लेगा जिनके पास जुड़ने के दोनों तरफ डेटा मिलान है । अगर हम सावधान नहीं होते हैं, तो इस परिणाम में हमारी कारों की मेज से वैध डेटा नहीं लौटाया जा सकता है यदि इस उपकुंजी में एक मिलान पंक्ति नहीं थी।

अब, पहले उपकेंद्र पर वापस देख रहे हैं, वहाँ कुछ सीमाएँ भी हैं। क्योंकि हम डेटा को एक पंक्ति में वापस खींच रहे हैं, हम केवल डेटा की एक पंक्ति को वापस खींच सकते हैं । selectक्वेरी के क्लॉज में उपयोग की जाने वाली उपश्रेणियाँ अक्सर केवल एक समुच्चय फ़ंक्शन का उपयोग करती हैं sum, जैसे कि count, maxया अन्य समान समुच्चय फ़ंक्शन। वे करने के लिए नहीं है , लेकिन यह अक्सर है कि वे कैसे लिखे गए हैं।

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

select
    ID,
    brand
from
    brands
where
    brand like '%o%'

+----+--------+
| ID | brand  |
+----+--------+
|  1 | Ford   |
|  2 | Toyota |
|  6 | Holden |
+----+--------+
3 rows in set (0.00 sec)

यह हमें ब्रांड आईडी और ब्रांड नामों की एक सूची देता है (दूसरा कॉलम केवल हमें ब्रांड दिखाने के लिए जोड़ा जाता है) जिसमें oनाम में अक्षर होता है।

अब, हम इस क्वेरी के परिणामों का उपयोग इस खंड में कर सकते हैं:

select
    a.ID,
    b.brand
from
    cars a
        join brands b
            on a.brand=b.ID
where
    a.brand in
        (
        select
            ID
        from
            brands
        where
            brand like '%o%'
        )

+----+--------+
| ID | brand  |
+----+--------+
|  2 | Ford   |
|  7 | Ford   |
|  1 | Toyota |
|  5 | Toyota |
|  8 | Toyota |
|  9 | Toyota |
| 11 | Toyota |
+----+--------+
7 rows in set (0.00 sec)

जैसा कि आप देख सकते हैं, भले ही उपश्रेणी तीन ब्रांड आईडी लौटा रही थी, हमारी कारों की तालिका में उनमें से केवल दो के लिए प्रविष्टियां थीं।

इस मामले में, आगे के विवरण के लिए, उपकुंजी काम कर रहा है जैसे कि हमने निम्नलिखित कोड लिखा है:

select
    a.ID,
    b.brand
from
    cars a
        join brands b
            on a.brand=b.ID
where
    a.brand in (1,2,6)

+----+--------+
| ID | brand  |
+----+--------+
|  1 | Toyota |
|  2 | Ford   |
|  5 | Toyota |
|  7 | Ford   |
|  8 | Toyota |
|  9 | Toyota |
| 11 | Toyota |
+----+--------+
7 rows in set (0.00 sec)

फिर से, आप देख सकते हैं कि कैसे डेटाबेस से लौटते समय एक उपकुंजी बनाम मैनुअल इनपुट ने पंक्तियों के क्रम को बदल दिया है।

जब हम उपश्रेणियों पर चर्चा कर रहे हैं, तो हम देखते हैं कि उपश्रेणी के साथ हम और क्या कर सकते हैं:

  • आप किसी अन्य उपकुंजी के भीतर एक उपश्रेणी रख सकते हैं, और इसी तरह इत्यादि। एक सीमा है जो आपके डेटाबेस पर निर्भर करती है, लेकिन कुछ पागल और उन्माद संबंधी प्रोग्रामर के पुनरावर्ती कार्यों से कम, अधिकांश लोग उस सीमा को कभी नहीं मारेंगे।
  • आप कई क्वेरीज़ को एक ही क्वेरी में, कुछ को selectक्लॉज़ में, कुछ को fromक्लॉज़ में और एक जोड़े को whereक्लॉज़ में रख सकते हैं - बस याद रखें कि आपके द्वारा डाला गया प्रत्येक आपके प्रश्न को और अधिक जटिल बना सकता है और इसमें अधिक समय लगने की संभावना है। निष्पादित।

यदि आपको कुछ कुशल कोड लिखने की आवश्यकता है, तो क्वेरी को कई तरीकों से लिखना और देखना (या तो इसे समय पर या एक व्याख्या योजना का उपयोग करके) लिखना फायदेमंद हो सकता है, जो आपके परिणाम प्राप्त करने के लिए इष्टतम क्वेरी है। पहला तरीका जो काम करता है वह हमेशा ऐसा करने का सबसे अच्छा तरीका नहीं हो सकता है।


नए देवों के लिए बहुत महत्वपूर्ण: सबक्वेरीज़ शायद हर परिणाम के लिए एक बार चलती हैं जब तक कि आप उप-क्वेरी को एक जोड़ के रूप में उपयोग नहीं कर सकते हैं (ऊपर दिखाया गया है)।
Xeoncross

59

भाग 3 - ट्रिक्स और कुशल कोड

MySQL () दक्षता में

मैंने सोचा था कि मैं कुछ अतिरिक्त बिट्स जोड़ूंगा, टिप्स और ट्रिक्स के लिए।

एक प्रश्न जो मैं देख रहा हूं वह काफी हद तक सही है, यह है कि मुझे दो तालिकाओं से गैर-मिलान वाली पंक्तियां कैसे मिलती हैं और मैं उत्तर को सबसे अधिक स्वीकृत चीजों के रूप में देखता हूं जैसे कि निम्नलिखित (हमारी कारों और ब्रांडों की तालिका के आधार पर - जिसे होल्डन के रूप में सूचीबद्ध किया गया है ब्रांड, लेकिन कारों की तालिका में दिखाई नहीं देता है):

select
    a.ID,
    a.brand
from
    brands a
where
    a.ID not in(select brand from cars)

और हाँ यह काम करेगा।

+----+--------+
| ID | brand  |
+----+--------+
|  6 | Holden |
+----+--------+
1 row in set (0.00 sec)

हालांकि यह कुछ डेटाबेस में कुशल नहीं है। यहाँ एक स्टैक ओवरफ्लो प्रश्न के बारे में एक लिंक दिया गया है , और इसके बारे में गहराई से लेख में एक उत्कृष्ट है यदि आप किटी ग्रिट्टी में जाना चाहते हैं।

संक्षिप्त उत्तर है, यदि ऑप्टिमाइज़र इसे कुशलता से नहीं संभालता है, तो गैर-सूचीबद्ध पंक्तियों को प्राप्त करने के लिए निम्नलिखित की तरह क्वेरी का उपयोग करना बेहतर हो सकता है:

select
    a.brand
from
    brands a
        left join cars b
            on a.id=b.brand
where
    b.brand is null

+--------+
| brand  |
+--------+
| Holden |
+--------+
1 row in set (0.00 sec)

उप-तालिका में उसी तालिका के साथ अद्यतन तालिका

आह, एक और पुराना लेकिन गुडी - पुराना आप FROM क्लॉज में अपडेट के लिए लक्ष्य तालिका 'ब्रांड' को निर्दिष्ट नहीं कर सकते

MySQL आपको update...एक ही टेबल पर सबसिलेक्ट के साथ क्वेरी चलाने की अनुमति नहीं देगा । अब, आप सोच रहे होंगे कि क्यों न इसे थप्पड़ मार दिया जाए, जहां क्लॉज सही है? लेकिन क्या होगा यदि आप max()तारीख के साथ केवल पंक्ति को अन्य पंक्तियों के एक समूह के साथ अपडेट करना चाहते हैं? आप वास्तव में ऐसा नहीं कर सकते जहां एक खंड में।

update 
    brands 
set 
    brand='Holden' 
where 
    id=
        (select 
            id 
        from 
            brands 
        where 
            id=6);
ERROR 1093 (HY000): You can't specify target table 'brands' 
for update in FROM clause

इसलिए, हम ऐसा नहीं कर सकते हैं? खैर, बिल्कुल नहीं। एक डरपोक वर्कअराउंड है कि आश्चर्यजनक रूप से बड़ी संख्या में उपयोगकर्ताओं को इसके बारे में पता नहीं है - हालांकि इसमें कुछ हैकरी शामिल हैं जिन्हें आपको ध्यान देने की आवश्यकता होगी।

आप सबक्विरी को एक और सबक्वेरी के भीतर चिपका सकते हैं, जो दो प्रश्नों के बीच पर्याप्त अंतर रखता है ताकि यह काम करे। हालाँकि, ध्यान दें कि किसी लेन-देन के भीतर क्वेरी को स्टिक करना सबसे सुरक्षित हो सकता है - इससे क्वेरी चल रहे समय में तालिकाओं में किए जा रहे किसी भी अन्य परिवर्तन को रोका जा सकेगा।

update 
    brands 
set 
    brand='Holden' 
where id=
    (select 
        id 
    from 
        (select 
            id 
        from 
            brands 
        where 
            id=6
        ) 
    as updateTable);

Query OK, 0 rows affected (0.02 sec)
Rows matched: 1  Changed: 0  Warnings: 0

3
बस यह नोट करना चाहते हैं कि कहां नहीं है () निर्माण एक 'दक्षता बिंदु' से बहुत समान है, लेकिन मेरी राय में पढ़ने / समझने में बहुत आसान है। तब फिर से, मेरा ज्ञान MSSQL तक सीमित है और अगर अन्य प्लेटफार्मों पर भी ऐसा ही हो तो मैं प्रतिज्ञा नहीं कर सकता।
डरपोक

मैंने दूसरे दिन इस प्रकार की तुलना करने की कोशिश की, जहां NOT IN () में कई सौ ID के बारे में एक सूची थी और इसमें और क्वेरी के सम्मिलित संस्करण में कोई अंतर नहीं था। शायद जब आप हजारों या अरबों में उठते हैं तो इससे फर्क पड़ता है।
बटल बस्कस

18

आप FROM कीवर्ड में कई प्रश्नों की अवधारणा का उपयोग कर सकते हैं। मैं आपको एक उदाहरण दिखाता हूं:

SELECT DISTINCT e.id,e.name,d.name,lap.lappy LAPTOP_MAKE,c_loc.cnty COUNTY    
FROM  (
          SELECT c.id cnty,l.name
          FROM   county c, location l
          WHERE  c.id=l.county_id AND l.end_Date IS NOT NULL
      ) c_loc, emp e 
      INNER JOIN dept d ON e.deptno =d.id
      LEFT JOIN 
      ( 
         SELECT l.id lappy, c.name cmpy
         FROM   laptop l, company c
         WHERE l.make = c.name
      ) lap ON e.cmpy_id=lap.cmpy

आप जितनी चाहें उतनी टेबल का उपयोग कर सकते हैं। बाहरी जोड़ और संघ का उपयोग करें, जहां कभी भी आवश्यक हो, यहां तक ​​कि तालिका उपश्रेणियों के अंदर भी।

यह एक बहुत ही आसान तरीका है, जिसमें टेबल और फ़ील्ड शामिल हैं।


8

आशा है कि यह तालिकाओं को खोजने के रूप में आप बात के माध्यम से पढ़ रहे हैं:

jsfiddle

mysql> show columns from colors;                                                         
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+           
| id    | int(3)      | NO   | PRI | NULL    | auto_increment |
| color | varchar(15) | YES  |     | NULL    |                |
| paint | varchar(10) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.