এসকিউএল যোগ দিন: এক থেকে বহু সম্পর্কের মধ্যে সর্বশেষ রেকর্ড নির্বাচন করা


298

ধরুন আমার কাছে গ্রাহকদের একটি টেবিল এবং ক্রয়ের টেবিল রয়েছে। প্রতিটি ক্রয় একজন গ্রাহকের অন্তর্ভুক্ত। আমি একটি নির্বাচনী বিবৃতিতে তাদের শেষ ক্রয়ের সাথে সমস্ত গ্রাহকের একটি তালিকা পেতে চাই। সেরা অনুশীলন কি? সূচী তৈরির বিষয়ে কোনও পরামর্শ?

আপনার উত্তরে এই টেবিল / কলামের নামগুলি ব্যবহার করুন:

  • গ্রাহক: আইডি, নাম
  • ক্রয়: আইডি, গ্রাহক_আইডি, আইটেম_আইডি, তারিখ

এবং আরও জটিল পরিস্থিতিতে, গ্রাহকের টেবিলের মধ্যে শেষ ক্রয়টি স্থাপন করে ডাটাবেসটিকে অস্বীকৃতি জানানো (পারফরম্যান্স-ওয়াইজ) সুবিধাজনক হবে?

যদি (ক্রয়) আইডিটি তারিখ অনুসারে বাছাইয়ের গ্যারান্টিযুক্ত থাকে তবে এর মতো কিছু ব্যবহার করে বিবৃতিগুলি সরল করা যেতে পারে LIMIT 1?


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

2
সম্পর্কিত: jan.kneschke.de/projects/mysql/groupwise-max
igorw

উত্তর:


449

এটি greatest-n-per-groupস্ট্যাকওভারফ্লোতে নিয়মিত উপস্থিত হওয়া সমস্যার উদাহরণ ।

এখানে আমি সাধারণত এটি সমাধান করার পরামর্শ দিই:

SELECT c.*, p1.*
FROM customer c
JOIN purchase p1 ON (c.id = p1.customer_id)
LEFT OUTER JOIN purchase p2 ON (c.id = p2.customer_id AND 
    (p1.date < p2.date OR (p1.date = p2.date AND p1.id < p2.id)))
WHERE p2.id IS NULL;

ব্যাখ্যা: একটি সারি দেওয়া p1, p2একই গ্রাহকের সাথে আর কোনও পরবর্তী তারিখের (বা সম্পর্কের ক্ষেত্রে, পরে id) কোনও সারি থাকা উচিত না । যখন আমরা এটি সত্য বলে পাই, তখন p1সেই গ্রাহকের জন্য সর্বাধিক সাম্প্রতিক ক্রয়।

ইনডেক্স সংক্রান্ত, আমি একটি যৌগ সূচী তৈরি চাই purchaseকলাম উপর ( customer_id, date, id)। এটি একটি আচ্ছাদন সূচক ব্যবহার করে বহিরাগত যোগদানের অনুমতি দিতে পারে। আপনার প্ল্যাটফর্মে পরীক্ষা করে নেওয়ার বিষয়টি নিশ্চিত করুন, কারণ অপ্টিমাইজেশন বাস্তবায়ন নির্ভর। অনুকূলকরণ পরিকল্পনাটি বিশ্লেষণ করতে আপনার আরডিবিএমএসের বৈশিষ্ট্যগুলি ব্যবহার করুন। যেমন EXPLAINমাইএসকিউএল অন।


কিছু লোক আমার উপরে দেখানো সমাধানের পরিবর্তে সাবকিউরিগুলি ব্যবহার করে তবে আমি দেখতে পাই যে আমার সমাধানগুলি সম্পর্কগুলি সমাধান করা সহজ করে।


3
সাধারণভাবে। তবে এটি আপনার ব্যবহার করা ডাটাবেসের ব্র্যান্ড এবং আপনার ডাটাবেজে ডেটা পরিমাণ এবং বন্টনের উপর নির্ভর করে। সুনির্দিষ্ট উত্তর পাওয়ার একমাত্র উপায় হ'ল আপনার ডেটার বিপরীতে উভয় সমাধান পরীক্ষা করা।
বিল কারভিন

27
আপনি যদি এমন গ্রাহককে অন্তর্ভুক্ত করতে চান যা কখনই কিনে নি, তবে JOIN ক্রয় পি 1 চালু করুন (সি। আইডি = পি 1 কাস্টমার_আইডি) বাম জোনে ক্রয় পি 1 চালু করুন (সি.আইডি = পি 1 কাস্টমার_আইডি)
গর্ডনএম

5
@ রসস, টাই সমাধানের জন্য আপনার কিছু অনন্য কলাম প্রয়োজন। রিলেশনাল ডাটাবেসে দুটি অভিন্ন সারি থাকার কোনও অর্থ হয় না।
বিল কারভিন

6
"WHERE p2.id IS NULL" এর উদ্দেশ্য কী?
ক্লু

3
1 টিরও বেশি ক্রয়ের রেকর্ড থাকলে এই সমাধানটি কেবলমাত্র কাজ করে। এখানে 1: 1 লিঙ্ক আছে, এটি কাজ করে না। সেখানে এটি "WHERE (p2.id IS NULL or p1.id = p2.id) থাকতে হবে
ব্রুনো জেনরিচ

126

সাব-সিলেক্ট করেও আপনি এটি করার চেষ্টা করতে পারেন

SELECT  c.*, p.*
FROM    customer c INNER JOIN
        (
            SELECT  customer_id,
                    MAX(date) MaxDate
            FROM    purchase
            GROUP BY customer_id
        ) MaxDates ON c.id = MaxDates.customer_id INNER JOIN
        purchase p ON   MaxDates.customer_id = p.customer_id
                    AND MaxDates.MaxDate = p.date

নির্বাচনের সমস্ত গ্রাহক এবং তাদের শেষ ক্রয়ের তারিখে যোগদান করা উচিত ।


4
ধন্যবাদ এটি কেবল আমাকে বাঁচিয়েছে - এই সমাধানটি আরও পুনর্ব্যবহারযোগ্য এবং রক্ষণাবেক্ষণযোগ্য বলে মনে হচ্ছে অন্যরা তালিকাভুক্ত করেছেন এটির পণ্য নির্দিষ্ট নয়
ডেভো

কোনও কেনাকাটা না থাকলেও আমি কীভাবে গ্রাহক পেতে চাইলে আমি কীভাবে এটি সংশোধন করব?
ক্লু

3
@clu: পরিবর্তনের INNER JOINএকটি থেকে LEFT OUTER JOIN
সাশা চেদিগোভ

3
দেখে মনে হচ্ছে যে সেদিন কেবলমাত্র একটি কেনাকাটা আছে। যদি দুটি থাকে তবে আপনি একজন গ্রাহকের জন্য দুটি আউটপুট সারি পাবেন, আমার মনে হয়?
আর্টফুলবোট

1
@ ইসতিয়াকহ্মেমেড - সর্বশেষ অন্তর্গত জয়েন সেই সর্বাধিক (তারিখ) মান নেয় এবং এটিকে উত্স সারণীতে ফিরিয়ে দেয়। যোগদান না করে, purchaseটেবিল থেকে আপনার কাছে কেবল তথ্যটি হ'ল তারিখ এবং গ্রাহক_আইডি, তবে কোয়েরিটি সারণী থেকে সমস্ত ক্ষেত্রের জন্য জিজ্ঞাসা করে।
হাসছে ভার্জিল

26

আপনি ডাটাবেস নির্দিষ্ট করেন নি। যদি এটি বিশ্লেষণমূলক ফাংশনগুলিকে মঞ্জুরি দেয় তবে গ্রোপ বাই এর চেয়ে এই পদ্ধতির ব্যবহারটি দ্রুততর হতে পারে (ওরাকলে স্পষ্টতই দ্রুত, সম্ভবত এসকিউএল সার্ভারের শেষ সংস্করণে দেরী, অন্যদের সম্পর্কে জানেন না)।

এসকিউএল সার্ভারে সিনট্যাক্সটি হ'ল:

SELECT c.*, p.*
FROM customer c INNER JOIN 
     (SELECT RANK() OVER (PARTITION BY customer_id ORDER BY date DESC) r, *
             FROM purchase) p
ON (c.id = p.customer_id)
WHERE p.r = 1

10
এটি প্রশ্নের ভুল উত্তর কারণ আপনি "ROW_NUMBER ()" এর পরিবর্তে "RANK ()" ব্যবহার করছেন। যখন দুটি ক্রয়ের সঠিক তারিখ ঠিক থাকে তখন র্যাঙ্ক আপনাকে সম্পর্কের একই সমস্যাটি দেয়। র‌্যাঙ্কিংয়ের কাজটি এটাই করে; যদি শীর্ষ 2 টি ম্যাচ করে তবে তারা উভয়ই 1 টির মান নির্ধারণ করে এবং তৃতীয় রেকর্ড 3 এর মান 3 পায় R
মাইকটিভি 20

4
এখানে স্কাল সার্ভার ২০০৮-তে কার্যকর কার্যকর পরিকল্পনা সহ বিল কারভিনের দৃষ্টিভঙ্গির বিপরীতে চেষ্টা করছিলাম ২০০৮ সালে আমি পেয়েছি বিল কার্বিনের ম্যাপালিনার পদ্ধতির বিপরীতে ৪৩% ব্যয় হয়েছে, যা এই উত্তরটির আরও মার্জিত বাক্য গঠন সত্ত্বেও, এখনও বিল এর সংস্করণ পক্ষে হবে!
শাওসন

26

আরেকটি উপায় হ'ল NOT EXISTSপরবর্তী ক্রয়ের জন্য পরীক্ষার জন্য আপনার যোগদানের শর্তটিতে একটি শর্ত ব্যবহার করা :

SELECT *
FROM customer c
LEFT JOIN purchase p ON (
       c.id = p.customer_id
   AND NOT EXISTS (
     SELECT 1 FROM purchase p1
     WHERE p1.customer_id = c.id
     AND p1.id > p.id
   )
)

AND NOT EXISTSআপনি সহজে কথায় অংশটি ব্যাখ্যা করতে পারেন ?
ইসতিয়াক আহমেদ

সাব নির্বাচন করে একটি উচ্চ আইডি সহ সারি আছে কিনা তা পরীক্ষা করে দেখুন। উচ্চতর আইডি সহ কোনওটি না পাওয়া গেলে আপনি কেবলমাত্র আপনার ফলাফলের সেটে একটি সারি পাবেন। এটি অনন্য সর্বোচ্চ হওয়া উচিত।
স্টিফান হ্যাবারেল

2
এটি আমার পক্ষে সর্বাধিক পঠনযোগ্য সমাধান। এটি গুরুত্বপূর্ণ যদি।
ফিউগিলেন

:) ধন্যবাদ। আমি সবসময় সবচেয়ে পাঠযোগ্য সমাধান জন্য আপ্রাণ চেষ্টা, কারণ যে হয় গুরুত্বপূর্ণ।
স্টিফান হ্যাবারেল

19

আমি এই থ্রেডটি আমার সমস্যার সমাধান হিসাবে পেয়েছি।

তবে আমি যখন তাদের চেষ্টা করেছি তখন পারফরম্যান্স কম ছিল। আরও ভালো পারফরম্যান্সের জন্য বেলো আমার পরামর্শ।

With MaxDates as (
SELECT  customer_id,
                MAX(date) MaxDate
        FROM    purchase
        GROUP BY customer_id
)

SELECT  c.*, M.*
FROM    customer c INNER JOIN
        MaxDates as M ON c.id = M.customer_id 

আশা করি এটি সহায়ক হবে।


আমি ব্যবহৃত 1 টি top 1এবং ordered it byম্যাক্সডেট পেতেdesc
রোশনা ওমর

1
এটি আমার ও ক্ষেত্রে সহজ (সহজলভ্য সমাধান) (অনেক গ্রাহক, কয়েকটি কেনাকাটা) 10% দ্রুত তারপরে @ স্টেফান হ্যাবারেলের সমাধান এবং গৃহীত উত্তরের চেয়ে 10 গুণ বেশি উত্তম
জুরজ বেজারুকা

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

সেরা উত্তর ইমো, পড়তে সহজ, ম্যাক্স () ধারাটি +
লিমিটেড

10

আপনি যদি PostgreSQL ব্যবহার করছেন তবে আপনি DISTINCT ONএকটি গ্রুপে প্রথম সারিটি ব্যবহার করতে পারেন ।

SELECT customer.*, purchase.*
FROM customer
JOIN (
   SELECT DISTINCT ON (customer_id) *
   FROM purchase
   ORDER BY customer_id, date DESC
) purchase ON purchase.customer_id = customer.id

পোস্টগ্রিএসকিউএল ডক্স - স্বতন্ত্র

নোট করুন যে DISTINCT ONক্ষেত্র (গুলি) - এখানে customer_id- অবশ্যই দলে থাকা বাম সর্বাধিক ক্ষেত্র (গুলি) এর সাথে মেলে ORDER BY

গুহাত: এটি একটি মানহীন ধারা।


পোস্টগ্র্রেএসকিউএল-র জন্য এটি সেরা উত্তর। রক্ষক!!!
অ্যাবেলাবেসনবী

8

এটি চেষ্টা করুন, এটি সাহায্য করবে।

আমি আমার প্রকল্পে এটি ব্যবহার করেছি।

SELECT 
*
FROM
customer c
OUTER APPLY(SELECT top 1 * FROM purchase pi 
WHERE pi.customer_id = c.Id order by pi.Id desc) AS [LastPurchasePrice]

উপন্যাস "পি" কোথা থেকে আসে?
টিয়াগোএ

এটি ভাল পারফরম্যান্স করে না .... চিরকাল নিয়ে গেছে যেখানে অন্যান্য উদাহরণগুলি আমার কাছে থাকা ডেটা সেটটিতে 2 সেকেন্ড সময় নিয়েছে ....
জোয়েল_জে

3

এসকিউএলাইটে পরীক্ষিত:

SELECT c.*, p.*, max(p.date)
FROM customer c
LEFT OUTER JOIN purchase p
ON c.id = p.customer_id
GROUP BY c.id

max()সমষ্টিগত ফাংশন নিশ্চিত করুন যে সর্বশেষ ক্রয় প্রতিটি গ্রুপ থেকে নির্বাচিত করা হয় (- যা স্বাভাবিকভাবে ক্ষেত্রে দেখা যায় কিন্তু ধরে নেয় যে তারিখ কলামটি একটি ফর্ম্যাটে আছে যেখানে সর্বোচ্চ () সর্বশেষ দেয়) করতে হবে। আপনি যদি একই তারিখে ক্রয় পরিচালনা করতে চান তবে আপনি ব্যবহার করতে পারেন max(p.date, p.id)

সূচকের ক্ষেত্রে, আমি কেনার ক্ষেত্রে (গ্রাহক_আইডি, তারিখ, [আপনার নির্বাচিত ক্ষেত্রে যে কোনও অন্য ক্রয় কলাম আপনি ফিরে আসতে চান]) এর সাথে ব্যবহার করব index

LEFT OUTER JOIN(যেমন বিরোধিতা INNER JOIN) নিশ্চিত যে গ্রাহকদের যে কোনো কেনাকাটা করার কখনও এছাড়াও অন্তর্ভুক্ত করা হয় করতে হবে।


টি সি
সিএল

1

দয়া করে এটি চেষ্টা করুন,

SELECT 
c.Id,
c.name,
(SELECT pi.price FROM purchase pi WHERE pi.Id = MAX(p.Id)) AS [LastPurchasePrice]
FROM customer c INNER JOIN purchase p 
ON c.Id = p.customerId 
GROUP BY c.Id,c.name;
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.