দীর্ঘতম ক্রমাগত ক্রম নির্বাচন করুন


12

আমি পোস্টগ্রেএসকিউএল 9.0 এ একটি কোয়েরি তৈরির চেষ্টা করছি যা একটি নির্দিষ্ট কলামের জন্য ক্রমাগত সারিগুলির দীর্ঘতম ক্রম পায়।

নিম্নলিখিত টেবিলটি বিবেচনা করুন:

lap_id (serial), lap_no (int), car_type (enum), race_id (int FK)

যেখানে lap_noপ্রতিটি জন্য অনন্য (race_id, car_type)

আমি চাইছি যে কোনও প্রদত্তের জন্য দীর্ঘতম ক্রম তৈরি করা উচিত race_idএবং car_typeএটি একটি int(বা দীর্ঘ) যা সর্বোচ্চ।

নিম্নলিখিত তথ্য সহ:

1, 1, red, 1
2, 2, red, 1
3, 3, red, 1
4, 4, red, 1
5, 1, blue, 1
6, 5, red, 1
7, 2, blue, 1
8, 1, green, 1

জন্য car_type = red and race_id = 1কোয়েরি ফিরে আসবে 5দীর্ঘতম ক্রম হিসাবে lap_noক্ষেত্র।

আমি একটি অনুরূপ প্রশ্ন পাওয়া এখানে অবশ্য আমার অবস্থা কিছুটা সহজবোধ্য।

(আমি car_typeসকল দৌড়ের জন্য প্রদত্ত দীর্ঘতম ক্রমটিও জানতে চাই , তবে এটি নিজেই কাজ করার পরিকল্পনা করছিলাম))

উত্তর:


20

আপনার বিবরণটির ফলাফলটি একটি সারণী সংজ্ঞায় এর ফলস্বরূপ :

CREATE TABLE tbl (
   lap_id   serial PRIMARY KEY
 , lap_no   int NOT NULL
 , car_type enum NOT NULL
 , race_id  int NOT NULL  -- REFERENCES ...
 , UNIQUE(race_id, car_type, lap_no)
);

এই শ্রেণীর সমস্যার সাধারণ সমাধান

দীর্ঘতম ক্রম পেতে (1 টি ফলাফল, সর্বোপরি সর্বাধিক, সম্পর্কগুলি থাকলে স্বেচ্ছাসেবী চয়ন করুন):

SELECT race_id, car_type, count(*) AS seq_len
FROM  (
   SELECT *, count(*) FILTER (WHERE step)
                      OVER (ORDER BY race_id, car_type, lap_no) AS grp
   FROM  (
      SELECT *, (lag(lap_no) OVER (PARTITION BY race_id, car_type ORDER BY lap_no) + 1)
                 IS DISTINCT FROM lap_no AS step
      FROM   tbl
      ) x
   ) y
GROUP  BY race_id, car_type, grp
ORDER  BY seq_len DESC
LIMIT  1;

count(*) FILTER (WHERE step)কেবল গণনা করা হয় TRUE(= পরবর্তী গ্রুপে পদক্ষেপ), যার ফলশ্রুতি প্রতিটি নতুন গোষ্ঠীর জন্য একটি নতুন সংখ্যা হয়।

এসও সম্পর্কিত সম্পর্কিত প্রশ্ন, পিএলপিএইচএসকিএল সহ একটি পদ্ধতিগত সমাধান বিশিষ্ট একটি উত্তর :

শীর্ষের প্রয়োজনীয়তা যদি পারফরম্যান্স হয় তবে এই বিশেষ ক্ষেত্রে plpgsql ফাংশনটি সাধারণত দ্রুত হয় কারণ এটি একক স্ক্যানের ফলাফল গণনা করতে পারে।

একটানা সংখ্যার জন্য দ্রুত

আমরা আরও সহজ এবং দ্রুত সংস্করণের জন্য ক্রমাগত lap_no একটি ক্রমকে সংজ্ঞায়িত করি এই সত্যটি আমরা বুঝতে পারি :

SELECT race_id, car_type, count(*) AS seq_len
FROM  (
   SELECT race_id, car_type
        , row_number() OVER (PARTITION BY race_id, car_type ORDER BY lap_no) - lap_no AS grp
   FROM   tbl
   ) x
GROUP  BY race_id, car_type, grp
ORDER  BY seq_len DESC
LIMIT  1;

একটানা কোল শেষ হয় grp। প্রতিটি অনুপস্থিত কোলে grpপ্রতি পার্টিশন কম হয় ।

এটি (race_id, car_type, lap_no)সত্তার উপর নির্ভর করে UNIQUE NOT NULL। নাল মান বা সদৃশ যুক্তি ভাঙ্গতে পারে।

জ্যাকের সহজ বিকল্প নিয়ে আলোচনা

@ জ্যাক এর সংস্করণ কার্যকরভাবে সব ল্যাপ (সারি), মোট ছাত্র যেখানে পূর্ববর্তী lap_noএই race_idএকই ছিল car_type। এটি সহজ এবং দ্রুত এবং সঠিক - যতক্ষণ car_typeনা প্রত্যেকের জন্য প্রতি এক করে ক্রম থাকতে পারে race_id

তবে এমন কোনও কাজের জন্য যে কোয়েরিটি সহজ হতে পারে, তবুও। এটা তোলে কথাটি অনুসরণ করবে যে সব lap_noপ্রতি (car_type, race_id)হতে হবে ক্রমানুসারে , এবং আমরা শুধু ল্যাপ গণনা পারে:

SELECT race_id, car_type, count(*) AS seq_len
FROM   tbl
GROUP  BY race_id, car_type
ORDER  BY seq_len DESC
LIMIT  1;

তাহলে, অপরপক্ষে, এক car_typeথাকতে পারে একাধিক পৃথক ক্রমের প্রতি race_id (এবং প্রশ্ন অন্যথায় নির্দিষ্ট করে না), জ্যাক এর সংস্করণ ব্যর্থ হবে।

প্রদত্ত জাতি / গাড়ী ধরণের জন্য দ্রুত

প্রশ্নের মন্তব্যে / স্পষ্টতার জবাবে: প্রদত্ত একটিতে কোয়েরি সীমাবদ্ধ করা অবশ্যই (race_id, car_type)এটি আরও দ্রুততর করবে , অবশ্যই:

SELECT count(*) AS seq_len
FROM  (
   SELECT row_number() OVER (ORDER BY lap_no) - lap_no AS grp
   FROM   tbl
   WHERE  race_id = 1
   AND    car_type = 'red'
   ) x
GROUP  BY grp
ORDER  BY seq_len DESC
LIMIT  1;

ডিবি <> ফিডল এখানে
পুরানো এসকিউএল ফিডল

সূচক

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

CREATE INDEX tbl_mult_idx ON tbl (race_id, car_type, lap_no);

আপনার টেবিল থাকে UNIQUEআমি শীর্ষ, যে শুধু এই (অনন্য) সূচকের সাথে অভ্যন্তরীণভাবে বাস্তবায়িত হয় এ অধিকৃত বাধ্যতা, এবং আপনি কি না অন্য সূচক তৈরি করতে হবে।


হাই এরউইন, ধন্যবাদ যে কাজটি করে, তবে এটি আমার ডাটাবেসে 17 ডলার লাগে! মনে করেন না আপনি কোনও সংশোধনী সরবরাহ করতে পারবেন তাই পুরো টেবিলের তুলনায় প্যারামিটার হিসাবে জাতি_আইড এবং কার_ টাইপ লাগে? (আমি এটি পুনরায় লেখার চেষ্টা করেছি এবং ত্রুটিগুলিতে চালিয়ে
যাচ্ছি

7

create table tbl (lap_no int, car_type text, race_id int);
insert into tbl values (1,'red',1),(2,'red',1),(3,'red',1),(4,'red',1),
                       (1,'blue',1),(5,'red',1),(2,'blue',1),(1,'green',1);
select car_type, race_id, sum(case when lap_no=(prev+1) then 1 else 0 end)+1 seq_len
from ( select *, lag(lap_no) over (partition by car_type, race_id order by lap_no) prev 
       from tbl ) z
group by car_type, race_id
order by seq_len desc limit 1;
/*
|car_type|race_id|seq_len|
|:-------|------:|------:|
|red     |      1|      5|
*/

অথবা সম্ভবত sum((lap_no=(prev+1))::integer)+1কিন্তু আমি নিশ্চিত যে সহজ পড়তে আছি
জ্যাক topanswers.xyz চেষ্টা বলে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.