2010-09-01 22 views
45

मेरे पास एक टेबल ग्राहक है जो ग्राहक_आईडी, ईमेल और संदर्भ संग्रहीत करता है। एक अतिरिक्त तालिका ग्राहक_डेटा है जो ग्राहक को किए गए परिवर्तनों का ऐतिहासिक रिकॉर्ड संग्रहीत करती है, यानी जब कोई बदलाव होता है तो कोई नई पंक्ति डाली जाती है।MySQL केवल हाल ही की पंक्ति में शामिल हों?

किसी तालिका में ग्राहक की जानकारी प्रदर्शित करने के लिए, दोनों तालिकाओं को शामिल करने की आवश्यकता है, हालांकि ग्राहक_डेटा से केवल हालिया पंक्ति ग्राहक तालिका में शामिल होनी चाहिए।

यह थोड़ा और जटिल हो जाता है कि क्वेरी पेजिनेटेड है, इसलिए इसकी सीमा और ऑफसेट है।

मैं इसे MySQL के साथ कैसे कर सकता हूं? मुझे लगता है मैं वहाँ कहीं एक अलग डाल करने के लिए ...

क्षण में क्वेरी इस-

SELECT *, CONCAT(title,' ',forename,' ',surname) AS name 
FROM customer c 
INNER JOIN customer_data d on c.customer_id=d.customer_id 
WHERE name LIKE '%Smith%' LIMIT 10, 20 

Additionaly की तरह है चाहता हूँ, मैं सोच में सही मैं में की तरह साथ concat उपयोग कर सकते हैं इस तरफ?

(मुझे खुशी है कि आंतरिक शामिल हों उपयोग करने के लिए शामिल हों गलत प्रकार का हो सकता है। मैं वास्तव में कोई सुराग नहीं क्या अंतर अलग मिलती है के बीच है। मैं अब कि गौर करने के लिए जा रहा हूँ है!)

+0

कैसे ग्राहक इतिहास तालिका कैसा दिखाई देता है कर सकता है? सबसे हालिया पंक्ति कैसे निर्धारित की जाती है? क्या कोई टाइमस्टैम्प फ़ील्ड है? –

+0

सबसे हाल ही में केवल अंतिम पंक्ति डाली गई है - इसलिए इसकी प्राथमिक कुंजी उच्चतम संख्या है। – bcmcfc

+0

क्यों एक ट्रिगर नहीं? इस जवाब पर एक नज़र डालें: http://stackoverflow.com/questions/26661314/best-and-optimal-way-to-join-max-value-from-other-table/26664982#26664982 –

उत्तर

76

आप निम्न की कोशिश करना चाहते हो सकता है:

SELECT CONCAT(title, ' ', forename, ' ', surname) AS name 
FROM  customer c 
JOIN  (
       SELECT MAX(id) max_id, customer_id 
       FROM  customer_data 
       GROUP BY customer_id 
     ) c_max ON (c_max.customer_id = c.customer_id) 
JOIN  customer_data cd ON (cd.id = c_max.max_id) 
WHERE  CONCAT(title, ' ', forename, ' ', surname) LIKE '%Smith%' 
LIMIT  10, 20; 

ध्यान दें कि एक JOIN सिर्फ INNER JOIN के लिए एक पर्याय है।

टेस्ट मामला:

CREATE TABLE customer (customer_id int); 
CREATE TABLE customer_data (
    id int, 
    customer_id int, 
    title varchar(10), 
    forename varchar(10), 
    surname varchar(10) 
); 

INSERT INTO customer VALUES (1); 
INSERT INTO customer VALUES (2); 
INSERT INTO customer VALUES (3); 

INSERT INTO customer_data VALUES (1, 1, 'Mr', 'Bobby', 'Smith'); 
INSERT INTO customer_data VALUES (2, 1, 'Mr', 'Bob', 'Smith'); 
INSERT INTO customer_data VALUES (3, 2, 'Mr', 'Jane', 'Green'); 
INSERT INTO customer_data VALUES (4, 2, 'Miss', 'Jane', 'Green'); 
INSERT INTO customer_data VALUES (5, 3, 'Dr', 'Jack', 'Black'); 

परिणाम (LIMIT और WHERE बिना क्वेरी):

SELECT CONCAT(title, ' ', forename, ' ', surname) AS name 
FROM  customer c 
JOIN  (
       SELECT MAX(id) max_id, customer_id 
       FROM  customer_data 
       GROUP BY customer_id 
     ) c_max ON (c_max.customer_id = c.customer_id) 
JOIN  customer_data cd ON (cd.id = c_max.max_id); 

+-----------------+ 
| name   | 
+-----------------+ 
| Mr Bob Smith | 
| Miss Jane Green | 
| Dr Jack Black | 
+-----------------+ 
3 rows in set (0.00 sec) 
+1

विवरण के स्तर के लिए धन्यवाद जो आप वहां गए हैं। मुझे आशा है कि यह दूसरों को और साथ ही मुझे मदद करता है! – bcmcfc

+6

लंबे समय तक यह दृष्टिकोण प्रदर्शन समस्याओं को उत्पन्न कर सकता है क्योंकि इसे अस्थायी तालिका बनाने की आवश्यकता होगी। तो एक और समाधान (यदि संभव हो) ग्राहक_डेटा में एक नया बूलियन फ़ील्ड (is_last) जोड़ना है जिसे आपको हर बार एक नई प्रविष्टि जोड़ने के लिए अद्यतन करना होगा। अंतिम प्रविष्टि में is_last = 1 होगा, अन्य सभी इस ग्राहक के लिए - is_last = 0। – cephuo

+0

लोगों को (कृपया) निम्नलिखित उत्तर (डैनी कौल्मबे से) भी पढ़ना चाहिए, क्योंकि यह उत्तर (माफ करना डैनियल) लंबे प्रश्न/अधिक डेटा के साथ बहुत धीमा है। लोड करने के लिए 12 सेकंड के लिए मेरा पृष्ठ "प्रतीक्षा करें" बनाया; तो कृपया https://stackoverflow.com/a/35965649/2776747 भी देखें। मैंने इसे कई अन्य बदलावों के बाद तक नहीं देखा, इसलिए मुझे पता लगाने में बहुत लंबा लगा। – Art

0
SELECT CONCAT(title,' ',forename,' ',surname) AS name * FROM customer c 
INNER JOIN customer_data d on c.id=d.customer_id WHERE name LIKE '%Smith%' 

मैं तुम्हें c.id को

किसी और अद्यतन तालिका संरचना

+0

मैं downvoted गए क्योंकि मैंने आपके जवाब को गलत तरीके से पढ़ा है और मैंने शुरू में सोचा कि यह गलत है। जल्दबाजी एक बुरा परामर्शदाता है :-) – Wirone

0

यह एक अच्छा विचार है c.customer_id बदलने की जरूरत है लगता है कि "customer_data" तालिका में वास्तविक डेटा प्रवेश करने। इस डेटा के साथ आप अपनी इच्छानुसार "ग्राहक_डेटा" तालिका से सभी डेटा चुन सकते हैं।

10

customer_data में autoincrement स्तंभ यह मानकर Id नाम पर है, तो आप कर सकते हैं:

SELECT CONCAT(title,' ',forename,' ',surname) AS name * 
FROM customer c 
    INNER JOIN customer_data d 
     ON c.customer_id=d.customer_id 
WHERE name LIKE '%Smith%' 
    AND d.ID = (
       Select Max(D2.Id) 
       From customer_data As D2 
       Where D2.customer_id = D.customer_id 
       ) 
LIMIT 10, 20 
7

किसी के लिए जो काम करना चाहिए MySQL का पुराना संस्करण (प्री-5.0 आईएसएच) आप इस प्रकार की क्वेरी के लिए उप-प्रश्न करने में असमर्थ हैं। यहां वह समाधान है जो मैं करने में सक्षम था और यह बहुत अच्छा काम करता था।

SELECT MAX(d.id), d2.*, CONCAT(title,' ',forename,' ',surname) AS name 
FROM customer AS c 
LEFT JOIN customer_data as d ON c.customer_id=d.customer_id 
LEFT JOIN customer_data as d2 ON d.id=d2.id 
WHERE CONCAT(title, ' ', forename, ' ', surname) LIKE '%Smith%' 
GROUP BY c.customer_id LIMIT 10, 20; 

अनिवार्य रूप से इस ग्राहक से इसमें शामिल होने तो पाया अधिकतम आईडी पर डेटा तालिका में शामिल होने के अपने डेटा तालिका के अधिकतम आईडी जा रहे हैं। इसका कारण यह है कि समूह के अधिकतम का चयन करने से यह गारंटी नहीं मिलती है कि बाकी डेटा आईडी के साथ मेल नहीं खाता है जबतक कि आप इसे वापस नहीं ले जाते।

मैं MySQL के नए संस्करणों पर इस परीक्षण नहीं किया है, लेकिन यह 4.0.30 पर काम करता है।

+0

यह अपनी सादगी में उत्कृष्ट है। यह पहली बार मैंने कभी इस दृष्टिकोण को क्यों देखा है? ध्यान दें कि 'EXPLAIN' इंगित करता है कि यह एक अस्थायी तालिका और filesort का उपयोग करता है। अंत में 'ऑर्डर द्वारा ऑर्डर' जोड़ना फाइलोर्ट को मिटा देता है। – Timo

+0

मेरे पछतावा के लिए, मेरा खुद का, सुंदर समाधान मेरे डेटा के लिए 3.5 गुना तेज नहीं है। मैंने मुख्य तालिका और साथ में शामिल तालिकाओं की सबसे हालिया आईडी का चयन करने के लिए एक सबक्वायरी का उपयोग किया, और उसके बाद एक बाहरी क्वेरी जो सबक्वायरी का चयन करती है और शामिल तालिकाओं से वास्तविक डेटा पढ़ती है। मैं मुख्य टेबल पर 5 टेबल में शामिल हो रहा हूं, और जहां 1000 रिकॉर्ड्स का चयन करने वाली स्थिति के साथ परीक्षण कर रहा हूं। इंडेक्स इष्टतम हैं। – Timo

+0

मैं 'SELECT *, MAX (firstData.id), MAX (secondData.id) के साथ अपने समाधान का उपयोग कर रहा था [...]'। तर्कसंगत रूप से, 'मुख्य चयन करें' *, firstData2। *, SecondData2। *, MAX (firstData.id), MAX (secondData.id), [...] 'में बदलकर, मैं इसे काफी तेज़ी से बनाने में सक्षम था। यह प्राथमिक सूचकांक से सभी डेटा पढ़ने के बजाय, सूचकांक से केवल पढ़ने के लिए अनुमति देता है। अब सुक्वायरी-आधारित समाधान के रूप में सुंदर समाधान केवल 1.9 गुना लेता है। – Timo

31

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

SELECT c.*, 
FROM client AS c 
LEFT JOIN client_calling_history AS cch ON cch.client_id = c.client_id 
WHERE 
    cch.cchid = (
     SELECT MAX(cchid) 
     FROM client_calling_history 
     WHERE client_id = c.client_id AND cal_event_id = c.cal_event_id 
    ) 
+3

वाह मैं लगभग अविश्वास में हूं कि यह कितना प्रदर्शन अंतर है। यकीन नहीं है कि यह अभी तक इतना कठोर क्यों था, लेकिन अब तक यह इतना तेज था कि ऐसा लगता है कि मैं कहीं और गड़बड़ कर रहा हूं ... –

+1

मैं वास्तव में चाहता हूं कि मैं इसे एक से अधिक बार +1 कर सकता हूं ताकि इसे और अधिक देखा जा सके। मैंने इसका काफी परीक्षण किया है और किसी भी तरह से यह मेरे प्रश्नों को लगभग तात्कालिक बनाता है (वर्कबेंच सचमुच 0.000 सेकंड कहता है, यहां तक ​​कि 'sql_no_cache set' के साथ भी), जबकि शामिल होने में खोज करने के लिए कई सेकंड लग गए। अभी भी परेशान है, लेकिन मेरा मतलब है कि आप इस तरह के परिणामों के साथ बहस नहीं कर सकते हैं। –

+0

मुझे यकीन नहीं है कि यह क्यों तेज है, लेकिन मैंने सुना है कि MySQL हमेशा नीचे से शुरू होता है। तो शायद "SELECT MAX" क्वेरी बस जारी रहती है जहां यह थी और केवल जॉइन में रखे जाने पर हर बार दोहराए जाने की बजाय आईडी इंडेक्स की वजह से कुछ पंक्तियां चलाती हैं। –

0

इस

SELECT CONCAT(title, ' ', forename, ' ', surname) AS name 
FROM  customer c 
LEFT JOIN (
       SELECT * FROM customer_data ORDER BY id DESC 
     ) customer_data ON (customer_data.customer_id = c.customer_id) 
GROUP BY c.customer_id   
WHERE  CONCAT(title, ' ', forename, ' ', surname) LIKE '%Smith%' 
LIMIT  10, 20; 
संबंधित मुद्दे