প্রতি ব্যবহারকারীকে সাম্প্রতিকতম তারিখ সহ সারিটি নির্বাচন করুন


125

আমার কাছে ব্যবহারকারীর চেক-ইন এবং আউট টাইমের একটি টেবিল ("lms_attendance") রয়েছে যা দেখতে এরকম দেখাচ্ছে:

id  user    time    io (enum)
1   9   1370931202  out
2   9   1370931664  out
3   6   1370932128  out
4   12  1370932128  out
5   12  1370933037  in

আমি এই টেবিলটির এমন একটি ভিউ তৈরির চেষ্টা করছি যা ব্যবহারকারী আইডির প্রতি সাম্প্রতিকতম রেকর্ডটিকে আউটপুট দেয়, আমাকে "ইন" বা "আউট" মান দেওয়ার সময়, এরকম কিছু:

id  user    time    io
2   9   1370931664  out
3   6   1370932128  out
5   12  1370933037  in

আমি এখন পর্যন্ত বেশ কাছাকাছি, কিন্তু আমি বুঝতে পেরেছি যে দর্শনগুলি সাবকিউরিগুলি গ্রহণ করবে না, যা এটি আরও শক্ত করে তুলছে। আমার কাছে নিকটতম ক্যোয়ারীটি ছিল:

select 
    `lms_attendance`.`id` AS `id`,
    `lms_attendance`.`user` AS `user`,
    max(`lms_attendance`.`time`) AS `time`,
    `lms_attendance`.`io` AS `io` 
from `lms_attendance` 
group by 
    `lms_attendance`.`user`, 
    `lms_attendance`.`io`

তবে আমি যা পাই তা হ'ল:

id  user    time    io
3   6   1370932128  out
1   9   1370931664  out
5   12  1370933037  in
4   12  1370932128  out

যা নিকট, তবে নিখুঁত নয়। আমি জানি যে শেষ গ্রুপটি সেখানে হওয়া উচিত ছিল না তবে এটি ছাড়া এটি সর্বাধিক সাম্প্রতিক সময়ে ফিরে আসে, তবে এটির সাথে সম্পর্কিত আইও মান হয় না।

কোন ধারনা? ধন্যবাদ!



ম্যানুয়াল ফিরে যান। আপনি দেখতে পাবেন যে এটি (পারস্পরিক সম্পর্কযুক্ত এবং অযৌক্তিক) উপজাগুলির সাথে এবং ছাড়া উভয়ই এই সমস্যার সমাধান দেয়।
স্ট্রবেরি

@ বার্মার, প্রযুক্তিগতভাবে, যেমনটি আমি আমার উত্তরে উল্লেখ করেছি, এটি সর্বাধিক-এন-প্রতি-গ্রুপ ট্যাগ সহ সমস্ত 700 টি প্রশ্নের নকল ।
টিএমএস

@ প্রডিক্ল, 'আইও (এনাম)' কী?
মনিকা হেডনেক

আমার কাছে "আইও" নামে একটি কলাম ছিল যা "ইন বা আউট" এর অর্থ দাঁড়ায়, এটি একটি এনাম টাইপ ছিল "ইন" বা "আউট" এর সম্ভাব্য মানগুলির সাথে। লোকেরা কখন কোনও ক্লাসে এবং চেক আউট করে তা পরীক্ষা করে রাখার জন্য এটি ব্যবহার করা হয়েছিল।
কীথ

উত্তর:


199

প্রশ্ন:

SQLFIDDLEExample

SELECT t1.*
FROM lms_attendance t1
WHERE t1.time = (SELECT MAX(t2.time)
                 FROM lms_attendance t2
                 WHERE t2.user = t1.user)

ফলাফল:

| ID | USER |       TIME |  IO |
--------------------------------
|  2 |    9 | 1370931664 | out |
|  3 |    6 | 1370932128 | out |
|  5 |   12 | 1370933037 |  in |

সমাধান যা প্রতিবার কাজ করে:

SQLFIDDLEExample

SELECT t1.*
FROM lms_attendance t1
WHERE t1.id = (SELECT t2.id
                 FROM lms_attendance t2
                 WHERE t2.user = t1.user            
                 ORDER BY t2.id DESC
                 LIMIT 1)

2
কি দারুন! কেবল এই কাজটিই নয়, আমাকে এই কোয়েরি সহ একটি ভিউ তৈরি করার অনুমতি দেওয়া হয়েছিল যদিও এতে সাবকিউরিস রয়েছে। এর আগে, যখন আমি সাবকিউরিয়াস সমন্বিত একটি ভিউ তৈরি করার চেষ্টা করেছি, এটি আমাকে দেয়নি। কেন এটি অনুমোদিত কিন্তু অন্যটি নেই সে সম্পর্কে কোনও বিধি রয়েছে?
কিথ

খুব অদ্ভুত. অসংখ্য ধন্যবাদ! সম্ভবত এটি ছিল কারণ আমার সাবকোয়ারিটি একটি সিউডো টেবিল ছিল যা আমি ফর্ম নির্বাচন করছিলাম, যেখানে এই উদাহরণটি যেখানে দফায় ব্যবহৃত হয়েছিল।
কিথ

4
সাবকিউয়ের দরকার নেই! তদতিরিক্ত, একই সময়ে দুটি রেকর্ড থাকলে এই সমাধানটি কাজ করে না । প্রতিবার চাকাটিকে পুনরায় উদ্ভাবনের চেষ্টা করার দরকার নেই, কারণ এটি সাধারণ সমস্যা - পরিবর্তে ইতিমধ্যে পরীক্ষিত এবং অনুকূলিত সমাধানগুলির জন্য যান - @ প্রডিক্ল আমার উত্তর দেখুন।
টিএমএস

আহ, অন্তর্দৃষ্টি জন্য ধন্যবাদ! আমি আগামীকাল অফিসে থাকাকালীন নতুন কোডটি চেষ্টা করব।
কিথ

3
@ টিএমএস এই সমাধানটি কার্যকর করে যদি রেকর্ডগুলির ঠিক একই সময় থাকে, যেহেতু ক্যোয়ারীটি সর্বাধিক আইডি সহ রেকর্ডটি সনাক্ত করে। এটি সূচিত করে যে টেবিলের সময়টি সন্নিবেশের সময়, যা একটি ভাল ধারনা নাও হতে পারে। পরিবর্তে আপনার সমাধান টাইমস্ট্যাম্পগুলির সাথে তুলনা করে এবং যখন দুটি টাইমস্ট্যাম্প অভিন্ন হয়, আপনি সর্বাধিক আইডি দিয়ে সারিটিও ফিরিয়ে দেন। সুতরাং, আপনার সমাধানটিও ধরে নিয়েছে যে এই টেবিলের টাইমস্ট্যাম্প সন্নিবেশয়ের ক্রমের সাথে সম্পর্কিত, যা আপনার উভয় প্রশ্নের সাথে সবচেয়ে বড় ত্রুটি।
ওয়েবওয়ান্ডার

73

নতুন করে চাকা চেষ্টা, এই যেমন করার কোন প্রয়োজন নেই সাধারণ সর্বশ্রেষ্ঠ-এন-প্রতি-গ্রুপ সমস্যা । খুব সুন্দর সমাধান উপস্থাপন করা হয়

আমি সাবকিউরিটি ছাড়াই সর্বাধিক সরল সমাধান ( এসকিউএলফিডাল, জাস্টিনের আপডেট হওয়া দেখুন ) পছন্দ করি ( সুতরাং ভিউগুলিতে ব্যবহার করা সহজ):

SELECT t1.*
FROM lms_attendance AS t1
LEFT OUTER JOIN lms_attendance AS t2
  ON t1.user = t2.user 
        AND (t1.time < t2.time 
         OR (t1.time = t2.time AND t1.Id < t2.Id))
WHERE t2.user IS NULL

এটি একই ক্ষেত্রে কার্যকর হয় যেখানে একই গ্রুপের মধ্যে একই বৃহত্তর মান সহ দুটি পৃথক রেকর্ড রয়েছে - যার সাথে কৌশলটি ধন্যবাদ (t1.time = t2.time AND t1.Id < t2.Id)। আমি এখানে যা করছি তা নিশ্চিত করেই বলা হয় যে একই ব্যবহারকারীর দু'টি রেকর্ড একই সময়ে কেবল একজনকে বেছে নেওয়া হয়। মাপদণ্ডটি Idঅন্য কিছু কিনা তা আসলে কী আসে যায় না - মূলত কোনও মানদণ্ড যা অনন্য বলে নিশ্চিত হয় তা এখানে কাজ করে।


1
সর্বাধিক ব্যবহার t1.time < t2.timeএবং কমপক্ষে হবে t1.time > t2.timeযা আমার প্রাথমিক স্বজ্ঞানের বিপরীত।
কেউই নয়

1
@ J.Money কারণ অন্তর্নিহিত অস্বীকৃতি লুকানো হল: আপনি T1 থেকে সকল রেকর্ড নির্বাচন যা না T2 থেকে সংশ্লিষ্ট রেকর্ড যেখানে t1.time < t2.timeশর্ত প্রযোজ্য :-)
জেনকিন্স টিএমএস

4
WHERE t2.user IS NULLকিছুটা অদ্ভুত। এই রেখাটি কী ভূমিকা পালন করে?
tumultous_rooster

1
জাস্টিন পোস্ট করা গৃহীত উত্তরটি আরও অনুকূল হতে পারে। গৃহীত উত্তরটি টেবিলের প্রাথমিক কীতে একটি পশ্চাদপদ সূচক স্ক্যান ব্যবহার করে, সীমা অনুসরণ করে সারণীর ক্রম স্ক্যান করে। অতএব, গৃহীত উত্তর অতিরিক্ত সূচকের সাথে ব্যাপকভাবে অনুকূল করা যায়। এই ক্যোয়ারীটি একটি সূচক দ্বারাও অনুকূলিত করা যেতে পারে, কারণ এটি দুটি সিক্যুয়েন্স স্ক্যান করে, তবুও একটি হ্যাশ এবং সিক্যুয়েন্স স্ক্যানের ফলাফলগুলির একটি "হ্যাশ-অ্যান্টি-জয়েন" এবং অন্যান্য সিকোয়েন্স স্ক্যানের হ্যাশ অন্তর্ভুক্ত রয়েছে। সত্যিকার অর্থে আরও অনুকূল কী এর ব্যাখ্যাতে আমি আগ্রহী।
ওয়েবওয়ান্ডার

@ টিএমএস আপনি কি OR (t1.time = t2.time AND t1.Id < t2.Id))বিভাগটি পরিষ্কার করতে পারবেন ?
ওলেগ কুটস

6

@ টিএমএস উত্তরের ভিত্তিতে, আমি এটি পছন্দ করি কারণ সাবকিউয়ের কোনও প্রয়োজন নেই তবে আমি মনে করি অংশটি বাদ দেওয়া 'OR'যথেষ্ট বুঝতে এবং পড়ার পক্ষে যথেষ্ট এবং সহজ হবে।

SELECT t1.*
FROM lms_attendance AS t1
LEFT JOIN lms_attendance AS t2
  ON t1.user = t2.user 
        AND t1.time < t2.time
WHERE t2.user IS NULL

আপনি যদি নাল সময়ের সাথে সারিগুলিতে আগ্রহী না হন তবে আপনি সেগুলিকে ক্লজটিতে ফিল্টার করতে পারেন WHERE:

SELECT t1.*
FROM lms_attendance AS t1
LEFT JOIN lms_attendance AS t2
  ON t1.user = t2.user 
        AND t1.time < t2.time
WHERE t2.user IS NULL and t1.time IS NOT NULL

ছেড়ে যাওয়া হচ্ছে ORপার্ট দুই রেকর্ড একই থাকতে পারে যদি সত্যিই একটি খারাপ ধারণা time
টিএমএস

পারফরম্যান্সের জন্য আমি এই সমাধানটি এড়াতে চাই। @ ওলেগকুটস যেমন উল্লেখ করেছেন, এটি মাঝ থেকে বড় ডেটা সেটগুলিতে খুব ধীর হয়ে যায়।
পিটার মিডলি

4

ইতিমধ্যে সমাধান হয়েছে, তবে কেবল রেকর্ডের জন্য, আরেকটি পদ্ধতির মধ্যে দুটি মতামত তৈরি করা হবে ...

CREATE TABLE lms_attendance
(id int, user int, time int, io varchar(3));

CREATE VIEW latest_all AS
SELECT la.user, max(la.time) time
FROM lms_attendance la 
GROUP BY la.user;

CREATE VIEW latest_io AS
SELECT la.* 
FROM lms_attendance la
JOIN latest_all lall 
    ON lall.user = la.user
    AND lall.time = la.time;

INSERT INTO lms_attendance 
VALUES
(1, 9, 1370931202, 'out'),
(2, 9, 1370931664, 'out'),
(3, 6, 1370932128, 'out'),
(4, 12, 1370932128, 'out'),
(5, 12, 1370933037, 'in');

SELECT * FROM latest_io;

এসকিউএল ফিডল এ এটি কর্মে দেখতে এখানে ক্লিক করুন


1
অনুসরণ করার জন্য ধন্যবাদ! হ্যাঁ, যদি কোনও সহজ উপায় না থাকে তবে আমি একাধিক মতামত তৈরি করতে যাচ্ছিলাম। আবার ধন্যবাদ
কিথ

0
select b.* from 

    (select 
        `lms_attendance`.`user` AS `user`,
        max(`lms_attendance`.`time`) AS `time`
    from `lms_attendance` 
    group by 
        `lms_attendance`.`user`) a

join

    (select * 
    from `lms_attendance` ) b

on a.user = b.user
and a.time = b.time

ধন্যবাদ। আমি জানি আমি এটি একটি সাবকিউরি ব্যবহার করে করতে পারি, তবে আমি এটি একটি দৃশ্যে রূপান্তরিত করার প্রত্যাশা করছিলাম এবং এটি এএফআইএকে দর্শনগুলিতে সাবক্রিওরগুলিকে অনুমতি দেবে না। আমি কি প্রতিটি উপ-জিজ্ঞাস্যকে একটি ভিউ ইত্যাদিতে রূপান্তর করতে পারি?
কিথ

join (select * from lms_attendance ) b= join lms_attendance b
আজেফেরতি


0

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

প্রশ্ন:

DBFiddleExample

SELECT DISTINCT
FIRST_VALUE(ID) OVER (PARTITION BY lms_attendance.USER ORDER BY lms_attendance.TIME DESC) AS ID,
FIRST_VALUE(USER) OVER (PARTITION BY lms_attendance.USER ORDER BY lms_attendance.TIME DESC) AS USER,
FIRST_VALUE(TIME) OVER (PARTITION BY lms_attendance.USER ORDER BY lms_attendance.TIME DESC) AS TIME,
FIRST_VALUE(IO) OVER (PARTITION BY lms_attendance.USER ORDER BY lms_attendance.TIME DESC) AS IO
FROM lms_attendance;

ফলাফল:

| ID | USER |       TIME |  IO |
--------------------------------
|  2 |    9 | 1370931664 | out |
|  3 |    6 | 1370932128 | out |
|  5 |   12 | 1370933037 |  in |

জাস্টিন প্রস্তাবিত সমাধানটি ব্যবহার করে আমি যে সুবিধাটি দেখতে পাচ্ছি তা হ'ল এটি আপনাকে মধ্যবর্তী দর্শন বা সারণীর প্রয়োজন ছাড়াই সাবকিউরিয়ায় ব্যবহারকারীর প্রতি সাম্প্রতিক ডেটা (বা প্রতি আইডি, বা যাই হোক না কেন) দিয়ে সারিটি নির্বাচন করতে সক্ষম করে।

এবং আপনার HANA চালানোর ক্ষেত্রে এটি ~ 7 গুন দ্রুত: ডি


-1

ঠিক আছে, এটি হয় হ্যাক বা ত্রুটি-প্রবণ হতে পারে তবে কোনওভাবে এটি পাশাপাশি কাজ করছে-

SELECT id, MAX(user) as user, MAX(time) as time, MAX(io) as io FROM lms_attendance GROUP BY id;

-2

এই কোয়েরিটি চেষ্টা করে দেখুন:

  select id,user, max(time), io 
  FROM lms_attendance group by user;

এর একটি এসকিউএলফিডাল বানানোর চেষ্টা করুন। আপনি সম্ভবত এটি খুঁজে পাবেন idএবং ioঅ-গ্রেগেটেড কলাম, যা এ-তে ব্যবহার করা যায় না group by
দেবি মরগান

1
কোনও গ্যারান্টি নেই যে সর্বোচ্চ (সময়) সহ আইডি হবে, এটি গ্রুপের মধ্যে কোনও আইডি হতে পারে। এই সমস্যাটি আমি এখানে সমাধান করতে এসেছি, এখনও খুঁজছি
রোবস্রোব

-3

সম্ভবত আপনি ব্যবহারকারীর দ্বারা গ্রুপ করতে পারেন এবং তারপরে সময় ডেস্কের মাধ্যমে অর্ডার করতে পারেন। নীচের মত কিছু

  SELECT * FROM lms_attendance group by user order by time desc;

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