গ্রুপ বাই দফায় উপস্থিত থাকতে হবে বা একটি সামগ্রিক ফাংশনে ব্যবহার করা উচিত


276

আমার কাছে একটি টেবিল রয়েছে যা দেখতে এই আহ্বানকারীকে 'নির্মাতা' বলে মনে হচ্ছে

 cname  | wmname |          avg           
--------+-------------+------------------------
 canada | zoro   |     2.0000000000000000
 spain  | luffy  | 1.00000000000000000000
 spain  | usopp  |     5.0000000000000000

এবং আমি প্রতিটি নামের জন্য সর্বাধিক গড় নির্বাচন করতে চাই।

SELECT cname, wmname, MAX(avg)  FROM makerar GROUP BY cname;

তবে আমি একটি ত্রুটি পাব,

ERROR:  column "makerar.wmname" must appear in the GROUP BY clause or be used in an   aggregate function 
LINE 1: SELECT cname, wmname, MAX(avg)  FROM makerar GROUP BY cname;

সুতরাং আমি এই কাজ

SELECT cname, wmname, MAX(avg)  FROM makerar GROUP BY cname, wmname;

তবে এটি উদ্দেশ্যযুক্ত ফলাফলগুলি দেবে না এবং নীচে ভুল আউটপুট প্রদর্শিত হবে।

 cname  | wmname |          max           
--------+--------+------------------------
 canada | zoro   |     2.0000000000000000
 spain  | luffy  | 1.00000000000000000000
 spain  | usopp  |     5.0000000000000000

আসল ফলাফল হওয়া উচিত

 cname  | wmname |          max           
--------+--------+------------------------
 canada | zoro   |     2.0000000000000000
 spain  | usopp  |     5.0000000000000000

আমি কীভাবে এই সমস্যাটি স্থির করতে পারি?

দ্রষ্টব্য: এই টেবিলটি পূর্বের ক্রিয়াকলাপ থেকে তৈরি একটি দৃশ্য।



আমি বুঝতে পারছি না। কেন wmname="usopp"প্রত্যাশিত এবং উদাহরণস্বরূপ নয় wmname="luffy"?
AndreKR

উত্তর:


226

হ্যাঁ, এটি একটি সাধারণ সমষ্টিগত সমস্যা। এসকিউএল 3 (1999) এর আগে নির্বাচিত ক্ষেত্রগুলি অবশ্যই GROUP BYক্লজ [*] এ উপস্থিত থাকতে হবে ।

এই সমস্যাটি সমাধান করার জন্য আপনাকে অবশ্যই একটি উপ-কোয়েরিতে সমষ্টিটি গণনা করতে হবে এবং তারপরে আপনাকে যে অতিরিক্ত কলামগুলি দেখাতে হবে তা পেতে নিজের সাথে এটিতে যোগদান করতে হবে:

SELECT m.cname, m.wmname, t.mx
FROM (
    SELECT cname, MAX(avg) AS mx
    FROM makerar
    GROUP BY cname
    ) t JOIN makerar m ON m.cname = t.cname AND t.mx = m.avg
;

 cname  | wmname |          mx           
--------+--------+------------------------
 canada | zoro   |     2.0000000000000000
 spain  | usopp  |     5.0000000000000000

তবে আপনি উইন্ডো ফাংশনগুলিও ব্যবহার করতে পারেন যা সহজ দেখায়:

SELECT cname, wmname, MAX(avg) OVER (PARTITION BY cname) AS mx
FROM makerar
;

এই পদ্ধতির সাথে একমাত্র জিনিস এটি সমস্ত রেকর্ড দেখায় (উইন্ডো ফাংশনগুলি গ্রুপ করে না)। তবে এটি প্রতিটি সারিতে দেশের জন্য সঠিক (অর্থাত্ সর্বোচ্চ cnameস্তরের) প্রদর্শন করবে MAX, সুতরাং এটি আপনার উপর নির্ভর করবে:

 cname  | wmname |          mx           
--------+--------+------------------------
 canada | zoro   |     2.0000000000000000
 spain  | luffy  |     5.0000000000000000
 spain  | usopp  |     5.0000000000000000

(cname, wmname)সর্বাধিক মানের সাথে মেলে এমন একমাত্র টিউপস দেখানোর জন্য সমাধানটি তর্কসাপেক্ষভাবে কম মার্জিত , হ'ল:

SELECT DISTINCT /* distinct here matters, because maybe there are various tuples for the same max value */
    m.cname, m.wmname, t.avg AS mx
FROM (
    SELECT cname, wmname, avg, ROW_NUMBER() OVER (PARTITION BY avg DESC) AS rn 
    FROM makerar
) t JOIN makerar m ON m.cname = t.cname AND m.wmname = t.wmname AND t.rn = 1
;


 cname  | wmname |          mx           
--------+--------+------------------------
 canada | zoro   |     2.0000000000000000
 spain  | usopp  |     5.0000000000000000

[*]: আকর্ষণীয়ভাবে যথেষ্ট, যদিও চশমা অনুসারে ধরণের-গোষ্ঠীবিহীন ক্ষেত্রগুলি নির্বাচন করার অনুমতি দেয়, বড় ইঞ্জিনগুলি সত্যই এটি পছন্দ করে না বলে মনে হয়। ওরাকল এবং এসকিউএল সার্ভার এটিকে একেবারেই অনুমতি দেয় না। মাইএসকিএল এটি ডিফল্টরূপে অনুমতি দেয়, তবে এখন but.7 থেকে প্রশাসককে ONLY_FULL_GROUP_BYএই বৈশিষ্ট্যটি সমর্থন করার জন্য সার্ভার কনফিগারেশনে ম্যানুয়ালি এই বিকল্পটি সক্ষম করতে হবে ...


1
ধন্যবাদ সিনট্যাক্সটি মূল বিষয়, তবে যোগদানের সময় আপনাকে অবশ্যই এমএক্স এবং
গড়ের

1
হ্যাঁ আপনার সিনট্যাক্সটি সঠিক এবং ডুপ্লিকেটগুলি মুছে ফেলবে তবে আপনার শেষ ফলাফলের জন্য m.avg = t.mx প্রয়োজন (আপনি JOING লিখেছেন) উদ্দেশ্য ফলাফল পেতে
র্যান্ডমগুই

1
@ সেবাস এটি যোগদান না করেই করা যেতে পারে MAX(@ সাইপ্রুবের উত্তর দেখুন, আমার উত্তরে আরও একটি সমাধান রয়েছে) তবে আপনি যেভাবে করেন না তা নয়। প্রত্যাশিত আউটপুট পরীক্ষা করুন।
শূন্য323

1
@ সেবাস আপনার সমাধানটি কেবল একটি কলাম (ম্যাক্স avgপ্রতি cname) যুক্ত করেছে তবে এটি ফলাফলের সারিগুলিকে সীমাবদ্ধ করে না (যেমন ওপি চায়)) আসল ফলাফলগুলি প্রশ্নের অনুচ্ছেদে দেখুন ।
ypercubeᵀᴹ

1
বাঁক বন্ধ ONLY_FULL_GROUP_BY মাইএসকিউএল 5.7 উপায় সক্রিয় না এসকিউএল মান নির্দিষ্ট করে যখন কলাম থেকে বাদ দেওয়া যেতে পারে group by(অথবা Postgres মত মাইএসকিউএল আচরণ তোলে)। এটি কেবল পুরানো আচরণে ফিরে আসে যেখানে মাইএসকিউএল পরিবর্তে এলোমেলো (= "অনির্দিষ্ট") ফলাফল দেয়।
a_horse_with_no_name

126

পোস্টগ্রিসে, আপনি বিশেষ DISTINCT ON (expression)সিনট্যাক্সও ব্যবহার করতে পারেন :

SELECT DISTINCT ON (cname) 
    cname, wmname, avg
FROM 
    makerar 
ORDER BY 
    cname, avg DESC ;

5
কেউ যদি
গড়ের

@amenzhinsky আপনার অর্থ কি? কেউ যদি ফলাফলটি আলাদা আলাদা অর্ডের সাথে বাছাই করতে চায় BY cname?
ypercubeᵀᴹ

@ টাইপ्यूब, আসলে পিএসকিএল প্রথমে বাছাই করে এবং পরে DISTINCT প্রয়োগ করে। গড় অনুসারে বাছাইয়ের ক্ষেত্রে আমরা প্রতিটি সারির ন্যূনতম এবং সর্বাধিক মানগুলি বাছাইয়ের দিকের উপর নির্ভর করে বিভিন্ন ফলাফল
পাব

3
অবশ্যই. আমি পোস্ট করা ক্যোয়ারী আপনি যদি চালনা না করেন তবে আপনি বিভিন্ন ফলাফল পাবেন! যে হিসাবে "এটা আশানুরূপ কাজ না হবে" একই না ...
ypercubeᵀᴹ

1
@ ব্যাটফ্যান মনে রাখবেন যে এটি বেশ শীতল, কমপ্যাক্ট এবং লিখতে সহজ, তবে এই ধরণের প্রশ্নের জন্য এটি প্রায়শই সবচেয়ে কার্যকর উপায় নয়।
ypercubeᵀᴹ

27

group byনির্বাচনের ক্ষেত্রে অ-গোষ্ঠীভুক্ত এবং অ-সমষ্টিগত ক্ষেত্রগুলি নির্দিষ্ট করার ক্ষেত্রে সমস্যাটি হ'ল ইঞ্জিনটির কোন ক্ষেত্রে রেকর্ডের ক্ষেত্রটি এ ক্ষেত্রে ফিরে আসা উচিত তা জানার কোনও উপায় নেই। এটা কি প্রথম? এটা কি শেষ? সাধারণত কোনও রেকর্ড নেই যা প্রাকৃতিকভাবে একত্রিত ফলাফলের সাথে মিলে যায় ( minএবং maxব্যতিক্রমগুলিও)।

যাইহোক, সেখানে একটি কার্যকারিতা রয়েছে: প্রয়োজনীয় ক্ষেত্রটিও সংহত করে তুলুন। পোস্টগুলিতে, এটি কাজ করা উচিত:

SELECT cname, (array_agg(wmname ORDER BY avg DESC))[1], MAX(avg)
FROM makerar GROUP BY cname;

নোট করুন যে এটি সবগুলি নামের একটি অ্যারে তৈরি করে, औसत দ্বারা অর্ডার করে এবং প্রথম উপাদানটি দেয় (পোস্টগ্র্যাসে অ্যারেগুলি 1-ভিত্তিক হয়)।


ভাল যুক্তি. যদিও এটি সম্ভবত মনে হয় যে প্রতিটি সারি থেকে অ-সমষ্টিগত ক্ষেত্রগুলিকে সারিটির অবদানের সমন্বিত ফলাফলের সাথে সংযুক্ত করতে ডিবি একটি বহিরাগত যোগদান করতে পারে। আমি প্রায়শই কৌতুহল ছিলাম যে কেন তাদের পক্ষে বিকল্প নেই। যদিও আমি কেবল এই বিকল্পটি সম্পর্কে অজ্ঞ হতে পারি :)
বেন সিমন্স

16
SELECT t1.cname, t1.wmname, t2.max
FROM makerar t1 JOIN (
    SELECT cname, MAX(avg) max
    FROM makerar
    GROUP BY cname ) t2
ON t1.cname = t2.cname AND t1.avg = t2.max;

rank() উইন্ডো ফাংশন ব্যবহার :

SELECT cname, wmname, avg
FROM (
    SELECT cname, wmname, avg, rank() 
    OVER (PARTITION BY cname ORDER BY avg DESC)
    FROM makerar) t
WHERE rank = 1;

বিঃদ্রঃ

হয় হয় প্রতি গ্রুপে একাধিক সর্বোচ্চ মান সংরক্ষণ করা হবে। আপনি যদি প্রতি গ্রুপে কেবল একক রেকর্ড চান তবে সর্বাধিক সমান পরিমাণে একাধিক রেকর্ড থাকলে আপনার @ ইয়পারক्यूबের উত্তরটি পরীক্ষা করা উচিত।


16

আমার জন্য, এটি একটি "সাধারণ সমষ্টি সমস্যা" সম্পর্কে নয়, কেবল একটি ভুল এসকিউএল কোয়েরি সম্পর্কে। "প্রতিটি নামের জন্য সর্বাধিক গড় নির্বাচন করুন ..." এর একক সঠিক উত্তরটি হ'ল

SELECT cname, MAX(avg) FROM makerar GROUP BY cname;

ফলাফলটি হবে:

 cname  |      MAX(avg)
--------+---------------------
 canada | 2.0000000000000000
 spain  | 5.0000000000000000

এই ফলাফলটি সাধারণভাবে এই প্রশ্নের উত্তর দেয় "প্রতিটি গ্রুপের জন্য সেরা ফলাফল কী?" । আমরা দেখতে পাচ্ছি যে স্পেনের জন্য সর্বোত্তম ফলাফল 5 এবং কানাডার পক্ষে সেরা ফলাফল 2 It এটি সত্য, এবং কোনও ত্রুটি নেই। আমাদের যদি ডাব্লুএমনেমও প্রদর্শন করতে হয়, আমাদের প্রশ্নের উত্তর দিতে হবে: " ফলাফল সেট থেকে ডাব্লু নেম নাম চয়ন করার নিয়ম কী ?" ভুলটি পরিষ্কার করতে ইনপুট ডেটাটি কিছুটা পরিবর্তন করা যাক:

  cname | wmname |        avg           
--------+--------+-----------------------
 spain  | zoro   |  1.0000000000000000
 spain  | luffy  |  5.0000000000000000
 spain  | usopp  |  5.0000000000000000

কোন ফল আপনি এই প্রশ্নের সাথে runnig উপর আশা করুন: SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname;? এটা করা উচিত spain+luffyনাকি spain+usopp? কেন? তা না হয় নির্ধারিত ক্যোয়ারীতে কিভাবে পছন্দ করে নিন "better" বা wmname যদি বিভিন্ন উপযুক্ত হয়, তাই ফলাফলের এছাড়াও নির্ধারিত করা হয় না। এজন্য এসকিউএল ইন্টারপ্রেটার একটি ত্রুটি ফেরায় - কোয়েরিটি সঠিক নয়।

অন্য কথায়, " spainগ্রুপে সেরা কে ?" প্রশ্নের সঠিক উত্তর নেই। । ইউফিপ-এর চেয়ে লফি ভাল নয়, কারণ ইউসপপের একই "স্কোর" রয়েছে।


এই সমাধানটি আমার পক্ষেও কাজ করেছিল। আমার ক্যোয়ারী সমস্যা ছিল কারণ আমার ওআরএম-তেও সম্পর্কিত প্রাথমিক কীটি অন্তর্ভুক্ত ছিল, এর ফলে নিম্নলিখিত ভুল কোয়েরির ফলস্বরূপ :,SELECT cname, id, MAX(avg) FROM makerar GROUP BY cname; যা এই বিভ্রান্তিকর ত্রুটি দেয়।
রবার্তো

1

এটি কাজ করে বলে মনে হচ্ছে

SELECT *
FROM makerar m1
WHERE m1.avg = (SELECT MAX(avg)
                FROM makerar m2
                WHERE m1.cname = m2.cname
               )

0

আমি সম্প্রতি এই সমস্যাটির মধ্যে দৌড়েছি, যখন ব্যবহার করে গণনা করার চেষ্টা করেছি case whenএবং দেখতে পেয়েছি যে whichএবং countবিবৃতিগুলির ক্রম পরিবর্তন করা সমস্যার সমাধান করে:

SELECT date(dateday) as pick_day,
COUNT(CASE WHEN (apples = 'TRUE' OR oranges 'TRUE') THEN fruit END)  AS fruit_counter

FROM pickings

GROUP BY 1

ব্যবহারের পরিবর্তে - পরে, যেখানে আমি ত্রুটি পেয়েছি যে আপেল এবং কমলাগুলি সামগ্রিক ফাংশনে উপস্থিত হওয়া উচিত

CASE WHEN ((apples = 'TRUE' OR oranges 'TRUE') THEN COUNT(*) END) END AS fruit_counter

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