MySQL INNER JOIN दूसरी टेबल से केवल एक पंक्ति का चयन करें


104

मेरे पास एक usersतालिका और एक paymentsतालिका है, प्रत्येक उपयोगकर्ता के लिए, जिनके पास भुगतान हैं, paymentsतालिका में कई संबद्ध भुगतान हो सकते हैं । मैं उन सभी उपयोगकर्ताओं का चयन करना चाहता हूं जिनके पास भुगतान है, लेकिन केवल उनके नवीनतम भुगतान का चयन करें। मैं इस एसक्यूएल की कोशिश कर रहा हूं, लेकिन मैंने पहले कभी भी नेस्टेड एसक्यूएल स्टेटमेंट की कोशिश नहीं की है, इसलिए मैं जानना चाहता हूं कि मैं क्या गलत कर रहा हूं। मदद की सराहना करें

SELECT u.* 
FROM users AS u
    INNER JOIN (
        SELECT p.*
        FROM payments AS p
        ORDER BY date DESC
        LIMIT 1
    )
    ON p.user_id = u.id
WHERE u.package = 1

जवाबों:


148

आपको उनकी नवीनतम तिथि प्रति प्राप्त करने के लिए एक उपश्रेणी होना आवश्यक है user ID

SELECT  a.*, c.*
FROM users a 
    INNER JOIN payments c
        ON a.id = c.user_ID
    INNER JOIN
    (
        SELECT user_ID, MAX(date) maxDate
        FROM payments
        GROUP BY user_ID
    ) b ON c.user_ID = b.user_ID AND
            c.date = b.maxDate
WHERE a.package = 1

1
@Fluffeh आपके पास बहुत अच्छा जवाब है Part 1 - Joins and Unions। :) बुकमार्क किया गया!
जॉन वू

1
धन्यवाद दोस्त, यह सिर्फ इस तरह की स्थितियों के लिए लिखा है, सही एसक्यूएल के साथ एक त्वरित जवाब पॉप अप करें, फिर उस राक्षस इंडेपथ को पढ़ने के लिए एक लिंक का सुझाव दें ताकि लोग सुझाए गए कोड को समझ सकें । इसे और विस्तार देने के लिए इसे जोड़ने की योजना है। यदि आप चाहें तो शामिल होने के लिए आपका स्वागत है, मुझे कोड के लिए एक
फिडेल को

@ जॉन अपने जवाब के लिए धन्यवाद, जिसने पूरी तरह से काम किया है। और क्यू एंड ए के लिए Fluffeh धन्यवाद, मैं इसे देख लेंगे!
वसीम

मुझे लगता है कि मेरा उत्तर अधिक सरल है और तेज है क्योंकि मैं सिर्फ एक आंतरिक जुड़ाव का उपयोग कर रहा हूं। शायद मैं गलत हूँ?
मिहाई मेटी सेप

2
क्या आंतरिक क्वेरी के बिना इस क्वेरी को करने का कोई तरीका है? मैं तालिका सी से अधिकतम लौटना चाहता हूं या अगर कोई पंक्तियां मेल नहीं खातीं तो वापस शून्य हो जाएं। जॉइन को लेफ्ट जॉइन में बदलना स्पष्ट रूप से काम नहीं करता है।
स्कॉट

32
SELECT u.*, p.*
FROM users AS u
INNER JOIN payments AS p ON p.id = (
    SELECT id
    FROM payments AS p2
    WHERE p2.user_id = u.id
    ORDER BY date DESC
    LIMIT 1
)

यह समाधान स्वीकृत उत्तर से बेहतर है क्योंकि यह उसी उपयोगकर्ता और तिथि के साथ कुछ भुगतान होने पर सही ढंग से काम करता है।


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

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

@ HameesA.Khan, मैंने प्रश्नों के निष्पादन की जांच नहीं की है। आप सही हो सकते हैं, लेकिन स्वीकृत समाधान एक 3-द्विसंयोजक जुड़ता है जो धीमा भी हो सकता है। मुझे डर है कि ट्वीक नहीं होगा यह मामूली (यह सवाल का विषय है)।
चालाकी

12
SELECT u.*, p.*, max(p.date)
FROM payments p
JOIN users u ON u.id=p.user_id AND u.package = 1
GROUP BY u.id
ORDER BY p.date DESC

इस चक्रफल को देखें


6
limit 1खंड केवल 1 उपयोगकर्ता जो क्या ओ पी चाहता है नहीं है वापस आ जाएगी।
फुलफे

6
@MateiMihai, यह काम नहीं करता है। क्वेरी केवल अधिकतम दिनांक देती है, न कि अधिकतम दिनांक वाली पूरी पंक्ति। आप इसे फिडल में देख सकते हैं: dateकॉलम अलग है max(p.date)। यदि आप paymentsतालिका में अधिक कॉलम जोड़ते हैं (उदाहरण के लिए cost), तो वह सभी कॉलम आवश्यक पंक्ति से नहीं होंगे
zxcat

3
   SELECT u.* 
        FROM users AS u
        INNER JOIN (
            SELECT p.*,
             @num := if(@id = user_id, @num + 1, 1) as row_number,
             @id := user_id as tmp
            FROM payments AS p,
                 (SELECT @num := 0) x,
                 (SELECT @id := 0) y
            ORDER BY p.user_id ASC, date DESC)
        ON (p.user_id = u.id) and (p.row_number=1)
        WHERE u.package = 1

2

आपकी क्वेरी के साथ दो समस्याएं हैं:

  1. प्रत्येक तालिका और उपश्रेणी को एक नाम की आवश्यकता होती है, इसलिए आपको उप-नाम का नाम देना होगा INNER JOIN (SELECT ...) AS p ON ...
  2. आपके पास जो उपकुंजी है, उसमें केवल एक पंक्ति की अवधि होती है, लेकिन आप वास्तव में प्रत्येक उपयोगकर्ता के लिए एक पंक्ति चाहते हैं । उसके लिए आपको अधिकतम तिथि प्राप्त करने के लिए एक क्वेरी की आवश्यकता है और फिर पूरी पंक्ति प्राप्त करने के लिए स्वयं से वापस जुड़ना होगा।

यह मानते हुए कि payments.dateप्रयास के लिए कोई संबंध नहीं हैं :

    SELECT u.*, p.* 
    FROM (
        SELECT MAX(p.date) AS date, p.user_id 
        FROM payments AS p
        GROUP BY p.user_id
    ) AS latestP
    INNER JOIN users AS u ON latestP.user_id = u.id
    INNER JOIN payments AS p ON p.user_id = u.id AND p.date = latestP.date
    WHERE u.package = 1

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

मैंने अपने मामले में यह सबसे तेज पाया। मेरे द्वारा किया गया एकमात्र परिवर्तन जहां उप-क्वेरी में चयनित उपयोगकर्ता डेटा को फ़िल्टर करने के लिए उप क्वेरी में जोड़ा गया है, From payments as p Where p.user_id =@user_idक्योंकि क्वेरी पूरी तालिका पर एक समूह कर रही है।
विकाश राते

2

@ जॉन वू के जवाब से मुझे इसी तरह की समस्या हल करने में मदद मिली। मैंने सही उत्तर निर्धारित करके उसके उत्तर में सुधार किया है। यह मेरे लिए काम किया है:

SELECT  a.*, c.*
FROM users a 
    INNER JOIN payments c
        ON a.id = c.user_ID
    INNER JOIN (
        SELECT user_ID, MAX(date) as maxDate FROM
        (
            SELECT user_ID, date
            FROM payments
            ORDER BY date DESC
        ) d
        GROUP BY user_ID
    ) b ON c.user_ID = b.user_ID AND
           c.date = b.maxDate
WHERE a.package = 1

मुझे यकीन नहीं है कि यह कितना कुशल है, हालांकि।



1

Matei Mihai ने एक सरल और कुशल समाधान दिया, लेकिन यह तब तक काम नहीं करेगा, जब तक कि इसे MAX(date)सेलेक्टेड हिस्से में नहीं रखा जाएगा, तो यह क्वेरी बन जाएगी:

SELECT u.*, p.*, max(date)
FROM payments p
JOIN users u ON u.id=p.user_id AND u.package = 1
GROUP BY u.id

और ऑर्डर करने से समूह बनाने में कोई फर्क नहीं पड़ेगा लेकिन यह समूह द्वारा प्रदान किए गए अंतिम परिणाम का आदेश दे सकता है। मैंने इसकी कोशिश की और यह मेरे लिए काम कर गया।


1

मेरा उत्तर सीधे @valex से बहुत उपयोगी है, अगर आपको ORDER BY खंड में कई कॉल की आवश्यकता है।

    SELECT u.* 
    FROM users AS u
    INNER JOIN (
        SELECT p.*,
         @num := if(@id = user_id, @num + 1, 1) as row_number,
         @id := user_id as tmp
        FROM (SELECT * FROM payments ORDER BY p.user_id ASC, date DESC) AS p,
             (SELECT @num := 0) x,
             (SELECT @id := 0) y
        )
    ON (p.user_id = u.id) and (p.row_number=1)
    WHERE u.package = 1

1

आप यह कोशिश कर सकते हैं:

SELECT u.*, p.*
FROM users AS u LEFT JOIN (
    SELECT *, ROW_NUMBER() OVER(PARTITION BY userid ORDER BY [Date] DESC) AS RowNo
    FROM payments  
) AS p ON u.userid = p.userid AND p.RowNo=1

1
हालांकि यह कोड स्निपेट प्रश्न को हल कर सकता है, जिसमें स्पष्टीकरण सहित वास्तव में आपकी पोस्ट की गुणवत्ता में सुधार करने में मदद करता है। याद रखें कि आप भविष्य में पाठकों के लिए प्रश्न का उत्तर दे रहे हैं, और उन लोगों को आपके कोड सुझाव के कारणों का पता नहीं चल सकता है।
एलेसियो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.