পোস্টগ্র্রেএসকিউএলে গ্রুপযুক্ত লিমিটেড: প্রতিটি গ্রুপের জন্য প্রথম এন সারিগুলি দেখায়?


179

কাস্টম কলাম দ্বারা আদেশ করা প্রতিটি গ্রুপের জন্য আমাকে প্রথম এন সারি নেওয়া দরকার।

নিম্নলিখিত সারণী দেওয়া:

db=# SELECT * FROM xxx;
 id | section_id | name
----+------------+------
  1 |          1 | A
  2 |          1 | B
  3 |          1 | C
  4 |          1 | D
  5 |          2 | E
  6 |          2 | F
  7 |          3 | G
  8 |          2 | H
(8 rows)

প্রতিটি বিভাগ_আইডের জন্য আমার প্রথম 2 টি সারি ( নাম অনুসারে অর্ডার করা ) দরকার , এর মতো ফলাফল:

 id | section_id | name
----+------------+------
  1 |          1 | A
  2 |          1 | B
  5 |          2 | E
  6 |          2 | F
  7 |          3 | G
(5 rows)

আমি PostgreSQL 8.3.5 ব্যবহার করছি।

উত্তর:


279

নতুন সমাধান (PostgreSQL 8.4)

SELECT
  * 
FROM (
  SELECT
    ROW_NUMBER() OVER (PARTITION BY section_id ORDER BY name) AS r,
    t.*
  FROM
    xxx t) x
WHERE
  x.r <= 2;

8
এটি পোস্টগ্রিসকিউএল 8.4 এর সাথেও কাজ করে (উইন্ডো ফাংশনগুলি 8.4 দিয়ে শুরু হয়)।
ব্রুনো

2
দলবদ্ধ সীমা করতে পাঠ্যপুস্তকের উত্তর
পিগিগবক্স

4
অসাধারণ! এটি নির্দোষভাবে কাজ করে। আমি যদিও কৌতূহলী, এটি করার কোনও উপায় আছে কি group by?
নুরশমিক

1
যারা লক্ষ লক্ষ সারিগুলির মতো কাজ করে এবং এটি করার জন্য সত্যিকারের পারফরম্যান্ট উপায়ের সন্ধান করেন - পোস্টের উত্তর হ'ল উপায়। যথাযথ সূচী দিয়ে টাই মশলা করতে ভুলে যাবেন না।
পরিশ্রমী কী প্রেসার

37

V9.3 থেকে আপনি একটি পার্শ্বযুক্ত যোগদান করতে পারেন

select distinct t_outer.section_id, t_top.id, t_top.name from t t_outer
join lateral (
    select * from t t_inner
    where t_inner.section_id = t_outer.section_id
    order by t_inner.name
    limit 2
) t_top on true
order by t_outer.section_id;

এটা দ্রুত হতে পারে তবে অবশ্যই আপনার ডেটা এবং ব্যবহারের ক্ষেত্রে বিশেষভাবে পারফরম্যান্সটি পরীক্ষা করা উচিত।


4
খুব ক্রিপ্টিক সমাধান আইএমও, বিশেষত সেই নামগুলি সহ, তবে একটি ভাল।
ভিলাসভ

1
JOIN পার্শ্বীয় সঙ্গে এই সমাধান হতে পারে বাতায়নযুক্ত ফাংশন এক (কিছু ক্ষেত্রে) উপরের তুলনায় উল্লেখযোগ্যভাবে দ্রুততর যদি আপনি সূচক আছে t_inner.nameকলাম
মধ্যে Artur Rashitov

ক্যোয়ারীটি স্বতঃ-যোগদান না করে তা বোঝা সহজ। সেক্ষেত্রে distinctদরকার নেই। পোস্ট পোস্টের লিঙ্কে একটি উদাহরণ দেখানো হয়েছে।
গিলসবি

বাবু, এই মন খারাপ। 9 সেকেন্ডের পরিবর্তে 120 মিমি "ROW_NUMBER" সমাধান সহ পেয়েছে। ধন্যবাদ!
পরিশ্রমী কী প্রেসার

কীভাবে আমরা টি_টপ এর সমস্ত কলাম নির্বাচন করতে পারি। টি টেবিলটিতে একটি জসন কলাম রয়েছে এবং আমি যখন নির্বাচন করি তখন " distinct t_outer.section_id, t_top.*
জসন পোস্টগ্রাস

12

এখানে আরও একটি সমাধান রয়েছে (পোস্টগ্রিসকিউএল <= 8.3)।

SELECT
  *
FROM
  xxx a
WHERE (
  SELECT
    COUNT(*)
  FROM
    xxx
  WHERE
    section_id = a.section_id
  AND
    name <= a.name
) <= 2

2
SELECT  x.*
FROM    (
        SELECT  section_id,
                COALESCE
                (
                (
                SELECT  xi
                FROM    xxx xi
                WHERE   xi.section_id = xo.section_id
                ORDER BY
                        name, id
                OFFSET 1 LIMIT 1
                ),
                (
                SELECT  xi
                FROM    xxx xi
                WHERE   xi.section_id = xo.section_id
                ORDER BY 
                        name DESC, id DESC
                LIMIT 1
                )
                ) AS mlast
        FROM    (
                SELECT  DISTINCT section_id
                FROM    xxx
                ) xo
        ) xoo
JOIN    xxx x
ON      x.section_id = xoo.section_id
        AND (x.name, x.id) <= ((mlast).name, (mlast).id)

কোয়েরিটি আমার প্রয়োজনের খুব কাছাকাছি, এটি 2 টিরও কম সারি সহ বিভাগগুলি দেখায় না, অর্থাত্ ID = 7 সহ সারিটি ফিরে আসে না। অন্যথায় আমি আপনার পদ্ধতির পছন্দ।
কাউবার সাপরেভ

আপনাকে ধন্যবাদ, আমি ঠিক কলের সাথে একই সমাধানে এসেছি, তবে আপনি দ্রুত ছিলেন। :-)
কাউবার সাপরেভ

প্রকৃতপক্ষে সর্বশেষ JOIN সাব-ক্লজটি এখানে সরল করা যেতে পারে: ... এবং x.id <= (মালস্ট) .আইডি হিসাবে ইতিমধ্যে নাম ক্ষেত্র অনুসারে চয়ন করা হয়েছে, না?
কাউবার সাপরেভ

@ কুবার: আপনার উদাহরণে name'গুলি এবং id' গুলি একই ক্রমে সাজানো হয়েছে, তাই আপনি এটি দেখতে পাবেন না। বিপরীত ক্রমে নামগুলি তৈরি করুন এবং আপনি দেখতে পাবেন যে এই প্রশ্নের বিভিন্ন ফলাফল পাওয়া যায়।
কাসনসুই

2
        -- ranking without WINDOW functions
-- EXPLAIN ANALYZE
WITH rnk AS (
        SELECT x1.id
        , COUNT(x2.id) AS rnk
        FROM xxx x1
        LEFT JOIN xxx x2 ON x1.section_id = x2.section_id AND x2.name <= x1.name
        GROUP BY x1.id
        )
SELECT this.*
FROM xxx this
JOIN rnk ON rnk.id = this.id
WHERE rnk.rnk <=2
ORDER BY this.section_id, rnk.rnk
        ;

        -- The same without using a CTE
-- EXPLAIN ANALYZE
SELECT this.*
FROM xxx this
JOIN ( SELECT x1.id
        , COUNT(x2.id) AS rnk
        FROM xxx x1
        LEFT JOIN xxx x2 ON x1.section_id = x2.section_id AND x2.name <= x1.name
        GROUP BY x1.id
        ) rnk
ON rnk.id = this.id
WHERE rnk.rnk <=2
ORDER BY this.section_id, rnk.rnk
        ;

সিটিই এবং উইন্ডো ফাংশনগুলি একই সংস্করণ সহ প্রবর্তিত হয়েছিল, তাই আমি প্রথম সমাধানটির সুবিধা দেখতে পাচ্ছি না।
a_horse_with_no_name

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

পোস্টটি "postgresql" ট্যাগ করা হয় এবং পোস্টগ্রিএসকিউএল সংস্করণ যা সিটিই প্রবর্তন করে উইন্ডোটিং ফাংশনও প্রবর্তন করে। সুতরাং আমার মন্তব্য (আমি দেখতে পেয়েছি যে এটি পুরানো - এবং PG 8.3 এর
কোনওটি

পোস্টটিতে 8.3.5 উল্লেখ করা হয়েছে এবং আমি বিশ্বাস করি যে তারা 8.4 এ চালু হয়েছিল। পাশাপাশি: বিকল্প পরিস্থিতিতে, আইএমএইচও সম্পর্কে জানাও ভাল is
ওয়াইল্ডপ্লাজার

ঠিক আমার অর্থ: 8.3 এর সিটিই বা উইন্ডোংয়ের কোনও কাজ ছিল না। সুতরাং প্রথম সমাধানটি 8.3 এ কাজ করবে না
a_horse_with_no_name
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.