আমি কীভাবে একটি নির্বাচনের বর্তমান এবং পরবর্তী বৃহত্তর মান পেতে পারি?


18

আমার কলাম সহ একটি আইএনডিবিবি টেবিল 'আইডিটাইমস' (মাইএসকিউএল 5.0.22-লগ) রয়েছে

`id` int(11) NOT NULL,
`time` int(20) NOT NULL, [...]

একটি যৌগিক অনন্য কী সহ

UNIQUE KEY `id_time` (`id`,`time`)

সুতরাং আইডি প্রতি একাধিক টাইমস্ট্যাম্প এবং টাইমস্ট্যাম্পে একাধিক আইডি থাকতে পারে।

আমি একটি ক্যোয়ারী সেট আপ করার চেষ্টা করছি যেখানে আমি সমস্ত এন্ট্রি এবং প্রতিটি প্রবেশের পরবর্তী পরবর্তী সময়ের জন্য উপস্থিত থাকি, যদি এটি উপস্থিত থাকে তবে এটি অবশ্যই ফিরে আসবে যেমন:

+-----+------------+------------+
| id  | time       | nexttime   |
+-----+------------+------------+
| 155 | 1300000000 | 1311111111 |
| 155 | 1311111111 | 1322222222 |
| 155 | 1322222222 |       NULL |
| 156 | 1312345678 | 1318765432 |
| 156 | 1318765432 |       NULL |
+-----+------------+------------+

এই মুহূর্তে আমি অনেক দূরে আছি:

SELECT l.id, l.time, r.time FROM 
    idtimes AS l LEFT JOIN idtimes AS r ON l.id = r.id
    WHERE l.time < r.time ORDER BY l.id ASC, l.time ASC;

তবে অবশ্যই এটি r.time> l.টাইম দিয়ে সমস্ত সারি দেয় এবং কেবল প্রথমটিই নয় ...

আমার ধারণা আমার মতো সাব-সাবলেট দরকার lect

SELECT outer.id, outer.time, 
    (SELECT time FROM idtimes WHERE id = outer.id AND time > outer.time 
        ORDER BY time ASC LIMIT 1)
    FROM idtimes AS outer ORDER BY outer.id ASC, outer.time ASC;

তবে আমি কীভাবে বর্তমান সময়ের উল্লেখ করতে জানি না (আমি জানি উপরেরটি বৈধ এসকিউএল নয়)।

আমি কীভাবে এটি একটি একক ক্যোয়ারী দিয়ে করব (এবং আমি @ ভার্ভেবলগুলি ব্যবহার না করাই পছন্দ করব যা টেবিলে একসাথে এক সারি সারি হলেও শেষ মানটি মনে রাখার উপর নির্ভর করে)?

উত্তর:


20

একটি জয়েন করা আপনার প্রয়োজন হতে পারে এমন একটি জিনিস।

SELECT l.id, l.time, r.time FROM 
    idtimes AS l LEFT JOIN idtimes AS r ON l.id = r.id

আমি মনে করি বাহ্যিক যোগটি ইচ্ছাকৃত, এবং আপনি নাল পেতে চাইছেন। আরও পরে।

WHERE l.time < r.time ORDER BY l.id ASC, l.time ASC;

আপনি কেবল আর। সারিতে সর্বনিম্ন (MIN) সময় থাকে যা এল.টাইমের চেয়ে বেশি। এটি সেই জায়গা যেখানে আপনাকে সাবকিউরিং করা দরকার।

WHERE r.time = (SELECT MIN(time) FROM idtimes r2 where r2.id = l.id AND r2.time > l.time)

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

আপনি আপনার JOIN কে মুছে ফেলার মাধ্যমে এবং স্কেলার সাবকিউরিটি নির্বাচন করুন তালিকায় সরানোর মাধ্যমে এটি সমাধান করুন:

SELECT id, time, 
    (SELECT MIN(time) FROM idtimes sub 
        WHERE sub.id = main.id AND sub.time > main.time) as nxttime
  FROM idtimes AS main 

4

আমি সবসময় subqueries ব্যবহার করতে এড়াতে পারেন মধ্যে SELECTব্লক বা FROM, ব্লক করা হয়েছে কারণ এটি কোড "dirtier" এবং কখনও কখনও কম কার্যকরী করে তোলে।

আমি মনে করি এটি করার আরও একটি মার্জিত উপায় হ'ল:

1. এই বার তার চেয়ে অনেক বেশী সময় সারির

আপনি এই একটি করতে পারেন JOINমধ্যে idtimes একই যোগদান constraining নিজেই সঙ্গে টেবিল আইডি এবং বার তার চেয়ে অনেক বেশী সময় বর্তমান সারির।

আপনি ব্যবহার করা উচিত LEFT JOINসারি যেখানে আছে ব্যতীত এড়াতে বার বর্তমান সারির এক তার চেয়ে অনেক বেশী।

SELECT
    i1.id,
    i1.time AS time,
    i2.time AS greater_time
FROM
    idtimes AS i1
    LEFT JOIN idtimes AS i2 ON i1.id = i2.id AND i2.time > i1.time

সমস্যা যেমনটি আপনি উল্লেখ করেছেন, তা হ'ল আপনার একাধিক সারি রয়েছে যেখানে পরের_আর সময়ের চেয়ে সময়ের চেয়ে বড় ।

+-----+------------+--------------+
| id  | time       | greater_time |
+-----+------------+--------------+
| 155 | 1300000000 | 1311111111   |
| 155 | 1300000000 | 1322222222   |
| 155 | 1311111111 | 1322222222   |
| 155 | 1322222222 |       NULL   |
| 156 | 1312345678 | 1318765432   |
| 156 | 1318765432 |       NULL   |
+-----+------------+--------------+

২. সারিগুলি সন্ধান করুন যেখানে বৃহত্তর_কাল কেবলমাত্র বৃহত্তর নয়, পরের_সময় হয়

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

SELECT
    i1.id,
    i1.time AS time,
    i2.time AS next_time,
    i3.time AS intrudor_time
FROM
    idtimes AS i1
    LEFT JOIN idtimes AS i2 ON i1.id = i2.id AND i2.time > i1.time
    LEFT JOIN idtimes AS i3 ON i2.id = i3.id AND i3.time > i1.time AND i3.time < i2.time

ওপস, আমাদের এখনও একটি মিথ্যা পরের_সময়ের !

+-----+------------+--------------+---------------+
| id  | time       | next_time    | intrudor_time |
+-----+------------+--------------+---------------+
| 155 | 1300000000 | 1311111111   |         NULL  |
| 155 | 1300000000 | 1322222222   |    1311111111 |
| 155 | 1311111111 | 1322222222   |         NULL  |
| 155 | 1322222222 |       NULL   |         NULL  |
| 156 | 1312345678 | 1318765432   |         NULL  |
| 156 | 1318765432 |       NULL   |         NULL  |
+-----+------------+--------------+---------------+

WHEREনীচে সীমাবদ্ধতা যুক্ত করে কেবল এই ইভেন্টটি ঘটে এমন সারিগুলিকে ফিল্টার করুন

WHERE
    i3.time IS NULL

ভাল, আমাদের যা প্রয়োজন তা আছে!

+-----+------------+--------------+---------------+
| id  | time       | next_time    | intrudor_time |
+-----+------------+--------------+---------------+
| 155 | 1300000000 | 1311111111   |         NULL  |
| 155 | 1311111111 | 1322222222   |         NULL  |
| 155 | 1322222222 |       NULL   |         NULL  |
| 156 | 1312345678 | 1318765432   |         NULL  |
| 156 | 1318765432 |       NULL   |         NULL  |
+-----+------------+--------------+---------------+

আমি আশা করি আপনার 4 বছর পরেও একটি উত্তর প্রয়োজন!


যে চালাক। আমি নিশ্চিত না যদিও এটি বোঝা সহজ। আমি মনে করি যে আমরা যদি is nullএবং যোগটিকে আই 3 এর সাথে প্রতিস্থাপন করি where not exists (select 1 from itimes i3 where [same clause])তবে কোডটি আমরা কী প্রকাশ করতে চাই তার আরও ঘনিষ্ঠভাবে প্রতিফলিত করবে।
অ্যান্ড্রু স্পেন্সার

THX বন্ধু তুমি আমার (পরের দিন) বাঁচিয়েছ!
জাকব

2

সমাধানটি উপস্থাপনের আগে আমার মনে রাখা উচিত এটি সুন্দর নয়। AUTO_INCREMENTআপনার টেবিলে যদি কিছু কলাম থাকে তবে এটি আরও সহজ হবে (আপনি কি?)

SELECT 
  l.id, l.time, 
  SUBSTRING_INDEX(GROUP_CONCAT(r.time ORDER BY r.time), ',', 1)
FROM 
  idtimes AS l 
  LEFT JOIN idtimes AS r ON (l.id = r.id)
WHERE 
  l.time < r.time
GROUP BY
  l.id, l.time

ব্যাখ্যা:

  • আপনার হিসাবে একইভাবে যোগদান করুন: দুটি টেবিলের সাথে যোগ দিন, ডানটি কেবল উচ্চতর সময় পাবে
  • বাম টেবিল থেকে উভয় কলাম দ্বারা গ্রুপ: এটি নিশ্চিত করে যে আমরা সমস্ত (id, time)সংমিশ্রণগুলি পেয়েছি (যা স্বতন্ত্র হিসাবেও পরিচিত)।
  • প্রত্যেকের জন্য (l.id, l.time), প্রথমটির r.time চেয়ে বড় যা পান l.time। এটির r.timeমাধ্যমে প্রথমে অর্ডারের মাধ্যমে ঘটে GROUP_CONCAT(r.time ORDER BY r.time)প্রথম টোকেনটি দিয়ে কাটা দিয়ে SUBSTRING_INDEX

সৌভাগ্য, এবং, এই টেবিলটি বড় হলে ভাল পারফরম্যান্সের আশা করবেন না।


2

এছাড়াও আপনি কি একটি কাছ থেকে কি চান পেতে পারেন min()এবং GROUP BYকোন ভেতরের নির্বাচন সঙ্গে

SELECT l.id, l.time, min(r.time) 
FROM idtimes l 
LEFT JOIN idtimes r on (r.id = l.id and r.time > l.time)
GROUP BY l.id, l.time;

আমি প্রায় একটি মোটা অঙ্কের অর্থ বাজি ধরব যে অপটিমাইজার এটিকে যাইহোক যাইহোক এরউইন স্মাউটের জবাব হিসাবে একই জিনিস হিসাবে রূপান্তরিত করে, এবং এটি কোনও পরিষ্কার কিনা তা বিতর্কযোগ্য তবে এটি সম্পূর্ণতার জন্য রয়েছে ...


1
এর মূল্য কি, এসএমএসএস এবং এসকিউএল সার্ভার ২০১ your আপনার ক্যোয়ারী এরউইনের চেয়ে অনেক বেশি পছন্দ করেছে (২৪ রান ফলাফলের তুলনায় ২৪ রান ফলাফলের ২৪ কেজির ফলাফল সেট)
নাথান লাফার্টি

অ্যান্ড্রু মনে হচ্ছে আপনি বাজিটি হারিয়েছেন :-)
এরউইন স্মাট

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