মাইএসকিউএল ইনার জয়েন দ্বিতীয় টেবিল থেকে কেবল একটি সারি নির্বাচন করুন


110

আমার কাছে একটি 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

উত্তর:


156

প্রতি সর্বশেষতম তারিখটি পেতে আপনার একটি সাবকিউারি থাকা দরকার 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

4
@ ফ্লুফ আপনার একটি খুব সুন্দর উত্তর আছে Part 1 - Joins and Unions। :) বুকমার্ক!
জন উউ

4
ধন্যবাদ সাথী, ঠিক এই ধরণের পরিস্থিতিতে এটি লিখেছেন, ডান এসকিউএল দিয়ে একটি দ্রুত উত্তর পপ আপ করুন, তারপরে সেই দানবটি পড়ার লিঙ্কের পরামর্শ দিন যাতে লোকেরা প্রস্তাবিত কোডটি বুঝতে পারে । এটি আরও প্রসারিত করার জন্য এটি যুক্ত করার পরিকল্পনা করছে। আপনি যদি চান তাতে যোগদান করতে স্বাগতম, আমার
কোডটির

@ জোহানউউ আপনার উত্তরের জন্য ধন্যবাদ, এটি পুরোপুরি কার্যকর হয়েছে। এবং প্রশ্নোত্তর জন্য ফ্লাফিকে ধন্যবাদ, আমি এটি একবার দেখে নেব!
ওয়াসিম

আমি মনে করি যে আমার উত্তরটি আরও সহজ এবং দ্রুততর কারণ আমি কেবল একটি অভ্যন্তরীণ যোগদান ব্যবহার করছি। আমার ভুল হতেও পারে?
মিহাই মাতেই

4
অভ্যন্তরীণ যোগদান ছাড়া এই কোয়েরি করার কোন উপায় আছে? আমি টেবিল সি থেকে সর্বাধিক ফিরিয়ে দিতে চাই বা কোনও সারি মেলে না, তবে ফিরে যেতে চাই। বাম জোয়েন্টে জয়েন পরিবর্তন করা স্পষ্টতই কাজ করে না।
স্কট

36
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
)

বা

SELECT u.*, p.*
FROM users AS u
INNER JOIN payments AS p ON p.user_id = u.id
WHERE NOT EXISTS (
    SELECT 1
    FROM payments AS p2
    WHERE
        p2.user_id = p.user_id AND
        (p2.date > p.date OR (p2.date = p.date AND p2.id > p.id))
)

এই সমাধানগুলি গৃহীত উত্তরের চেয়ে ভাল কারণ একই ব্যবহারকারী এবং তারিখ সহ একাধিক অর্থ প্রদানের সময় তারা সঠিকভাবে কাজ করে। আপনি এসকিউএল ফিডল চেষ্টা করতে পারেন ।


এটি আপনার ব্যবহার করা একটি ভাল পদ্ধতির। তবে আমার কাছে একটির মতো পণ্যের বিরুদ্ধে একটি চিত্র আনার বিষয়ে প্রশ্ন রয়েছে। একটি পণ্যের অনেকগুলি (4) চিত্র রয়েছে তবে আমি কেবলমাত্র সেই পণ্যটির বিরুদ্ধে কেবল একটি চিত্র দেখাতে চাই।
আলী রাজা

আপনি কি মনে করেন না এটি ব্যবহার করা খুব ধীর হবে? যেমন আপনি অভ্যন্তরীণ যোগদানের জন্য আপনার সাব কোয়েরিতে প্রতিটি রেকর্ডের জন্য প্রক্রিয়া করছেন। স্বীকৃত উত্তরটি একটি ছোটখাটো ঝাঁকুনির পরে সেরা সম্ভব উত্তর হতে পারে।
হামেস এ খান খান

@ হামেস এ. খান, আমি কোয়েরি কার্যকারিতা পরীক্ষা করে দেখিনি। আপনি ঠিক থাকতে পারেন, তবে গৃহীত সমাধানটি একটি ত্রিমাত্রিক যোগ দেয় যা খুব ধীর হতে পারে। আমি ভয় করি যে টুইটটি ছোট হবে না (এটি প্রশ্নের বিষয়)।
পণ্য #

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
@ মাতিমিহাই, এটি কাজ করে না ক্যোয়ারীটি সর্বাধিক তারিখ সহ পুরো সারিটি নয়, কেবলমাত্র সর্বোচ্চ তারিখ দেয়। আপনি এটি ফ্রেডে দেখতে পারেন: 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. প্রতিটি টেবিল এবং subquery একটি নাম প্রয়োজন, তাই আপনাকে subquery নাম রাখতে হবে INNER JOIN (SELECT ...) AS p ON ...
  2. Subquery আপনি এটা শুধুমাত্র এক সারি সময়ের ফেরৎ আছে, কিন্তু আপনি আসলে এক সারি চান হিসাবে প্রত্যেক ব্যবহারকারীর জন্য । তার জন্য আপনার সর্বাধিক তারিখ পেতে একটি ক্যোয়ারী দরকার এবং তারপরে পুরো সারিটি পেতে ফিরে স্ব-যোগদান করুন।

ধরে নিই এর সাথে কোনও সম্পর্ক নেই 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

মেটেই মিহাই একটি সহজ এবং দক্ষ সমাধান দিয়েছেন তবে এটি MAX(date)SELECT অংশে না লাগিয়ে কাজ করবে না যাতে এই ক্যোয়ারীটি হয়ে উঠবে:

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 থেকে খুব অনুগ্রহ করে অনুপ্রাণিত হয়েছে, যদি আপনাকে আদেশের অধীনে আদেশের বেশ কয়েকটি কলসের প্রয়োজন হয়।

    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

4
এই কোড স্নিপেট একটি ব্যাখ্যা সহ প্রশ্নটি সমাধান করতে পারে, যদিও সত্যিই আপনার পোস্টের মান উন্নত করতে সহায়তা করে। মনে রাখবেন যে আপনি ভবিষ্যতে পাঠকদের জন্য প্রশ্নের উত্তর দিচ্ছেন, এবং সেই লোকেরা আপনার কোড পরামর্শের কারণগুলি জানেন না।
আলেসিও

0

এটি করা সহজ সরল অভ্যন্তরীণ যোগদান এবং তারপরে ব্যবহারকারী_আইডি দ্বারা গোষ্ঠীভুক্ত করুন এবং পেমেন্ট_আইডিতে সর্বাধিক সমষ্টিগত ফাংশনটি ব্যবহার করে আপনার টেবিলটি ব্যবহারকারী এবং পেমেন্ট কোয়েরি হিসাবে ধরে নেওয়া যায়

select user.id, max(payment.id) from user inner join payment on (user.id = payment.user_id) group by user.id

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.