পোস্টগ্রেএসকিউএল ডাইস্টিন্ট অন অর্ডার দ্বারা ভিন্ন


216

আমি এই কোয়েরিটি চালাতে চাই:

SELECT DISTINCT ON (address_id) purchases.address_id, purchases.*
FROM purchases
WHERE purchases.product_id = 1
ORDER BY purchases.purchased_at DESC

তবে আমি এই ত্রুটিটি পেয়েছি:

পিজি :: ত্রুটি: ত্রুটি: প্রকাশের উপর নির্বাচন পৃথক করা অবশ্যই প্রাথমিক অর্ডার বাই এক্সপ্রেশনের সাথে মেলে

address_idপ্রথম ORDER BYঅভিব্যক্তি হিসাবে যুক্ত করা ত্রুটিটি স্তব্ধ করে, তবে আমি সত্যিই বাছাই করা যুক্ত করতে চাই না address_id। আদেশ না দিয়ে কি করা সম্ভব address_id?


আপনার অর্ডার ধারাটি ঠিকানা_ইড নয় কিনেছে_আপনি আপনার প্রশ্নটি পরিষ্কার করে দিতে পারেন।
তেজা

আমার অর্ডার ক্রয় করেছে কারণ আমি এটি চাই, তবে পোস্টগ্রাসে ঠিকানাও জিজ্ঞাসা করা হয় (ত্রুটির বার্তা দেখুন)।
sl_bug

3
- সম্পূর্ণ উত্তর এখানে দেওয়া stackoverflow.com/questions/9796078/... ধন্যবাদ stackoverflow.com/users/268273/mosty-mostacho
sl_bug

ব্যক্তিগতভাবে আমি মনে করি যে অর্ডারটি অর্ডারের সাথে মিলানোর জন্য ডিস্টিন্ট অন দরকার খুব প্রশ্নবিদ্ধ, কারণ এগুলি পৃথক করার জন্য বৈধ ব্যবহারের বিভিন্ন ধরণের মামলা রয়েছে। যাঁরা একইরকম অনুভব করেন তাদের জন্য পোস্টগ্রাসক্লু.উভারসয়েজ এ একটি পোস্ট করার চেষ্টা করছে। postgresql.uservoice.com/forums/21853-general/suggestions/…
সেমিকোলন

ঠিক একই সমস্যা পেয়েছে এবং একই সীমাবদ্ধতার মুখোমুখি। এই মুহুর্তে আমি এটিকে একটি সাব-কোয়েরিতে ভেঙে অর্ডার দিয়েছি তবে এটি নোংরা অনুভব করে।
গাই পার্ক

উত্তর:


208

ডকুমেন্টেশন বলে:

DISTINCT ON (অভিব্যক্তি [, ...]) প্রতিটি সারিগুলির প্রথম সারিতে রাখে যেখানে প্রদত্ত প্রকাশগুলি সমান হিসাবে মূল্যায়ন করে। [...] নোট করুন যে কাঙ্ক্ষিত সারিটি প্রথমে উপস্থিত রয়েছে তা নিশ্চিত করতে অর্ডার বাই ব্যবহার না করা হলে প্রতিটি সেটের "প্রথম সারি" অপ্রত্যাশিত। [...] অভিব্যক্তি (গুলি) -এর DISTINCT অবশ্যই বাম দিকের অর্ডার বাই এক্সপ্রেশন (গুলি) এর সাথে মিলে যাবে।

অফিসিয়াল ডকুমেন্টেশন

সুতরাং আপনাকে address_idআদেশ অনুসারে যুক্ত করতে হবে।

বিকল্পভাবে, আপনি যদি পুরো সারিটি সন্ধান করছেন যা প্রতিটির জন্য সর্বাধিক কেনা পণ্য রয়েছে address_idএবং এর ফলাফল অনুসারে সাজানো হয়েছে purchased_atতবে আপনি গ্রুপ প্রতি সমস্যাটি সর্বাধিক এন সমাধান করার চেষ্টা করছেন যা নিম্নলিখিত পদ্ধতির মাধ্যমে সমাধান করা যেতে পারে:

বেশিরভাগ ডিবিএমএস-এ কাজ করা উচিত এমন সাধারণ সমাধান:

SELECT t1.* FROM purchases t1
JOIN (
    SELECT address_id, max(purchased_at) max_purchased_at
    FROM purchases
    WHERE product_id = 1
    GROUP BY address_id
) t2
ON t1.address_id = t2.address_id AND t1.purchased_at = t2.max_purchased_at
ORDER BY t1.purchased_at DESC

@ এইচকেএফ এর উত্তরের উপর ভিত্তি করে আরও একটি পোস্টগ্র্যাস এসকিউএল-ভিত্তিক সমাধান:

SELECT * FROM (
  SELECT DISTINCT ON (address_id) *
  FROM purchases 
  WHERE product_id = 1
  ORDER BY address_id, purchased_at DESC
) t
ORDER BY purchased_at DESC

এখানে সমস্যাটি স্পষ্ট, প্রসারিত এবং সমাধান করা হয়েছে: কিছু কলাম দ্বারা সাজানো সারি নির্বাচন করা হয়েছে এবং অন্যটিতে আলাদা


40
এটি কাজ করে তবে ভুল অর্ডার দেয়। এজন্য আমি আদেশের
ধারাটিতে ঠিকানা_আইড থেকে

1
ডকুমেন্টেশন পরিষ্কার: আপনি পারবেন না কারণ নির্বাচিত সারিটি অনির্দেশ্য হবে
মোস্তি মোস্তাচো

3
তবে সুস্পষ্ট ঠিকানাগুলির জন্য সর্বশেষ ক্রয় নির্বাচন করার অন্য কোনও উপায় থাকতে পারে?
sl_bug

1
আপনি purchases.purchased_at দ্বারা অর্ডার করার প্রয়োজন হলে, আপনি আপনার স্বতন্ত্র শর্ত purchased_at যোগ করতে পারেন: SELECT DISTINCT ON (purchases.purchased_at, address_id)। তবে একই ঠিকানা_আইডির সাথে দুটি কিনে ভিন্ন ভিন্ন ক্রয়কৃত মানগুলি প্রত্যাবর্তিত সেটে সদৃশ হয়ে যাবে। নিশ্চিত হয়ে নিন যে আপনি যে ডেটা জিজ্ঞাসা করছেন সে সম্পর্কে আপনি সচেতন।
ব্রেন্ডন বেনসন

23
প্রশ্নের স্পিরিট স্পষ্ট। শব্দার্থবিজ্ঞান বাছাই করার দরকার নেই। এটি দুঃখজনক যে গ্রহণযোগ্য এবং সর্বাধিক ভোট দেওয়া উত্তর আপনাকে সমস্যার সমাধান করতে সহায়তা করে না।
নিকোগা

55

আপনি একটি subquery এ ঠিকানার_ইড দিয়ে অর্ডার করতে পারেন, তারপরে বাইরের ক্যোয়ারিতে আপনি যা চান সেটি ক্রম করুন।

SELECT * FROM 
    (SELECT DISTINCT ON (address_id) purchases.address_id, purchases.* 
    FROM "purchases" 
    WHERE "purchases"."product_id" = 1 ORDER BY address_id DESC ) 
ORDER BY purchased_at DESC

3
তবে এটি কেবল একটি প্রশ্নের চেয়ে ধীর হবে, না?
sl_bug

2
খুব প্রান্তিক হ্যাঁ। যদিও আপনার কোনও ক্রয় রয়েছে your * আপনার আসলটিতে select, আমি মনে করি না এটি প্রোডাকশন কোড?
hkf

8
আমি যোগটি পোস্টের নতুন সংস্করণগুলির জন্য আপনার উপকৌটির উপন্যাসের প্রয়োজন need উদাহরণস্বরূপ: নির্বাচন * থেকে (।। স্বতন্ত্র চালু (address_id) purchases.address_id, কেনাকাটা নির্বাচন করুন "ক্রয়ের" কোথায় "ক্রয়ের" থেকে * "PRODUCT_ID" address_id DESC বাই = 1 অর্ডার) হিসাবে tmp, আদেশ দ্বারা DESC tmp.purchased_at
aembke

এটি address_idদুইবার ফিরে আসবে (প্রয়োজন ছাড়াই)। অনেক ক্লায়েন্টের নকল কলামের নাম নিয়ে সমস্যা রয়েছে। ORDER BY address_id DESCঅর্থহীন এবং বিভ্রান্তিকর। এটি এই ক্যোয়ারিতে দরকারী কিছু করে না। ফলাফল একই সঙ্গে সারি প্রতিটি সেট থেকে একটি অবাধ পিক হয় address_idসর্বশেষ সঙ্গে, না সারি purchased_at। অস্পষ্ট প্রশ্নটি স্পষ্টভাবে এর জন্য জিজ্ঞাসা করেনি, তবে এটি প্রায় অবশ্যই ওপির উদ্দেশ্য intention সংক্ষেপে: এই কোয়েরিটি ব্যবহার করবেন না । আমি ব্যাখ্যা সহ বিকল্প পোস্ট।
এরউইন ব্র্যান্ডসেটেটার

আমার জন্য কাজ করেছেন। দুর্দান্ত উত্তর।
ম্যাট ওয়েস্ট

46

একটি subquery এটি সমাধান করতে পারে:

SELECT *
FROM  (
    SELECT DISTINCT ON (address_id) *
    FROM   purchases
    WHERE  product_id = 1
    ) p
ORDER  BY purchased_at DESC;

নেতৃস্থানীয় মত প্রকাশ ORDER BY কলামগুলির সাথে একমত হতে হবে DISTINCT ON, যাতে আপনি একইভাবে বিভিন্ন কলাম দ্বারা অর্ডার করতে পারবেন না SELECT

ORDER BYআপনি যদি প্রতিটি সেট থেকে একটি নির্দিষ্ট সারি বাছাই করতে চান তবে কেবল সাবকিউরিতে একটি অতিরিক্ত ব্যবহার করুন :

SELECT *
FROM  (
    SELECT DISTINCT ON (address_id) *
    FROM   purchases
    WHERE  product_id = 1
    ORDER  BY address_id, purchased_at DESC  -- get "latest" row per address_id
    ) p
ORDER  BY purchased_at DESC;

যদি purchased_atহতে পারে তবে NULLবিবেচনা করুন DESC NULLS LAST। তবে আপনার সূচীটি ব্যবহার করার ইচ্ছা থাকলে তা নিশ্চিত করুন। দেখা:

সম্পর্কিত, আরও ব্যাখ্যা সহ:


আপনি DISTINCT ONকোনও মিল না করে ব্যবহার করতে পারবেন না ORDER BY। প্রথম ক্যোয়ারিতে ORDER BY address_idসাবকোয়ারির ভিতরে একটি প্রয়োজন ।
এরিস্টটল পাগাল্টজিস

4
@ অ্যারিস্টটল পেগাল্টজিস: তবে আপনি পারবেন । আপনি যেখান থেকে এটি পেয়েছেন, এটি ভুল। আপনি একই ক্যোয়ারী DISTINCT ONছাড়াই ব্যবহার করতে পারেন ORDER BY। আপনি এক্ষেত্রে DISTINCT ONক্লজ দ্বারা সংজ্ঞায়িত পিয়ারদের প্রতিটি সেট থেকে একটি স্বেচ্ছাসারি সারি পান । ম্যানুয়ালটিতে বিশদ এবং লিঙ্কগুলির জন্য এটি ব্যবহার করুন বা উপরের লিঙ্কগুলি অনুসরণ করুন। ORDER BYএকই ক্যোয়ারিতে (একই SELECT) কেবলমাত্র একমত হতে পারে না DISTINCT ON। আমি এটিও ব্যাখ্যা করেছিলাম।
এরউইন ব্র্যান্ডসটেটার

হু, আপনি ঠিক বলেছেন। ORDER BYদস্তাবেজে "অপ্রত্যাশিত" ব্যবহার করা না হলে "নোটের জড়িত হওয়া সম্পর্কে আমি অন্ধ ছিলাম কারণ এটি আমার কাছে বোধগম্য হয় না যে বৈশিষ্ট্যটি অবিচ্ছিন্ন মানগুলির সাথে মোকাবিলা করতে সক্ষম হয় ... তবুও আপনাকে অনুমতি দেবে না একটি সুস্পষ্ট অর্ডার দিয়ে এটি কাজে লাগান। বিরক্তিকর।
এরিস্টটল পাগাল্টজিস

@ অ্যারিস্টটেল পেগাল্টজিস: এটি কারণ, অভ্যন্তরীণভাবে পোস্টগ্রিস দুটি (কমপক্ষে) দুটি স্বতন্ত্র অ্যালগরিদম ব্যবহার করে: হয় বাছাই করা তালিকাটি হ্যাশ করুন বা হ্যাশ মানগুলির সাথে কাজ করুন - যেগুলি দ্রুত হওয়ার প্রতিশ্রুতি দেয়। পরবর্তী ক্ষেত্রে ফলাফল DISTINCT ONপ্রকাশের দ্বারা সাজানো হয় না (এখনও)।
এরউইন ব্র্যান্ডসটেটার

2
ধন্যবাদ. আপনার উত্তরগুলি সর্বদা স্ফটিক পরিষ্কার এবং সহায়ক!
আন্দ্রে দেইনকো

10

উইন্ডো ফাংশনটি এক পাসে এটি সমাধান করতে পারে:

SELECT DISTINCT ON (address_id) 
   LAST_VALUE(purchases.address_id) OVER wnd AS address_id
FROM "purchases"
WHERE "purchases"."product_id" = 1
WINDOW wnd AS (
   PARTITION BY address_id ORDER BY purchases.purchased_at DESC
   ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)

7
কেউ যদি ক্যোয়ারীটি ব্যাখ্যা করে দেয় তবে ভাল লাগবে।
গজুস

@ গজুস: সংক্ষিপ্ত বিবরণ: এটি কার্যকর হয় না, কেবল পৃথক প্রত্যাবর্তন করে address_id। নীতিটি কাজ করতে পারে , যদিও। সম্পর্কিত উদাহরণ: স্ট্যাকওভারফ্লো . com / a / 22064571 / 939860 বা স্ট্যাকওভারফ্লো . com / a / 11533808 / 939860 । তবে হাতের কাছে সমস্যাটির জন্য ছোট এবং / অথবা দ্রুততর প্রশ্ন রয়েছে।
এরউইন ব্র্যান্ডসটেটার

5

ফ্লাস্ক-এসকিউএএএলএলএকচেমি ব্যবহারকারী যে কোনও ব্যক্তির জন্য, এটি আমার পক্ষে কাজ করেছিল

from app import db
from app.models import Purchases
from sqlalchemy.orm import aliased
from sqlalchemy import desc

stmt = Purchases.query.distinct(Purchases.address_id).subquery('purchases')
alias = aliased(Purchases, stmt)
distinct = db.session.query(alias)
distinct.order_by(desc(alias.purchased_at))

2
হ্যাঁ, বা আরও সহজ, আমি ব্যবহার করতে সক্ষম হয়েছি:query.distinct(foo).from_self().order(bar)
লরেন্ট মেয়ার

@ লরেন্টমিয়ার আপনার মানে Purchases.query?
পুনরায়

হ্যাঁ, আমি পার্চেসেস.কোয়ারী বলতে চাইছিলাম
লরেন্ট মেয়ার

-2

আপনি ক্লজ দ্বারা গ্রুপ ব্যবহার করে এটিও করতে পারেন

   SELECT purchases.address_id, purchases.* FROM "purchases"
    WHERE "purchases"."product_id" = 1 GROUP BY address_id,
purchases.purchased_at ORDER purchases.purchased_at DESC

এটি ভুল ( purchasesকেবলমাত্র দুটি কলাম না থাকলে address_idএবং purchased_at)। এর কারণে GROUP BY, আপনাকে প্রতিটি কলামের গোষ্ঠীকরণের জন্য মূল্য না পাওয়ার জন্য একটি সামগ্রিক ফাংশন ব্যবহার করতে হবে, সুতরাং আপনি কুরুচিপূর্ণ এবং অদক্ষ জিমন্যাস্টিকের মধ্য দিয়ে না গেলে সমস্ত মান গ্রুপের বিভিন্ন সারি থেকে আসবে। এটি কেবল উইন্ডো ফাংশন ব্যবহার করে স্থির করা যেতে পারে GROUP BY
এরিস্টটল পাগাল্টজিস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.