দিনের অনন্য সংখ্যা সন্ধান করুন


11

আমি টেবিল থেকে প্রতিটি কর্মচারীর জন্য অনন্য কাজের দিনগুলির সন্ধানের জন্য একটি এসকিউএল কোয়েরি লিখতে চাই times

*---------------------------------------*
|emp_id  task_id  start_day   end_day   |
*---------------------------------------*
|  1        1     'monday'  'wednesday' |
|  1        2     'monday'  'tuesday'   |
|  1        3     'friday'  'friday'    |
|  2        1     'monday'  'friday'    |
|  2        1     'tuesday' 'wednesday' |
*---------------------------------------*

প্রত্যাশিত আউটপুট:

*-------------------*
|emp_id  no_of_days |
*-------------------*
|  1        4       |
|  2        5       |
*-------------------*

আমি কোয়েরিটি স্ক্যালফিল্ড লিখেছি যা আমাকে expectedআউটপুট দিচ্ছে তবে কৌতূহলের জন্য এই কোয়েরিটি লেখার আরও ভাল উপায় আছে কি? আমি কি ক্যালেন্ডার বা টেলি টেবিলটি ব্যবহার করতে পারি?

with days_num as  
(
  select
    *,
    case 
      when start_day = 'monday' then 1
      when start_day = 'tuesday' then 2
      when start_day = 'wednesday' then 3
      when start_day = 'thursday' then 4
      when start_day = 'friday' then 5
    end as start_day_num,

    case 
      when end_day = 'monday' then 1
      when end_day = 'tuesday' then 2
      when end_day = 'wednesday' then 3
      when end_day = 'thursday' then 4
      when end_day = 'friday' then 5
    end as end_day_num

  from times
),
day_diff as
(
  select
    emp_id,
    case
      when  
        (end_day_num - start_day_num) = 0
      then
        1
      else
        (end_day_num - start_day_num)
    end as total_diff
  from days_num  
)

select emp_id,
  sum(total_diff) as uniq_working_days
from day_diff
group by
  emp_id

কোন পরামর্শ মহান হবে।


মূল্যবোধের জন্য (1, 1, 'monday', 'wednesday'),(1, 2, 'monday', 'tuesday'),(1, 3, 'monday', 'tuesday');এমপিডে 3 স্বতন্ত্র দিন কাজ করেছে (সোমবার, মঙ্গলবার, বুধবার), ফিডল / ক্যোয়ারী 4
এলটিপিআর

1
@ এলটিআরটি এটি(1, 1, 'monday', 'wednesday'),(1, 2, 'monday', 'tuesday'),(1, 3, 'friday', 'friday');
উদ্যোগী

3
আপনার ক্যোয়ারী আসলে কাজ করে না। আপনি যদি ফলাফলটি পরিবর্তন 1 2 'monday' 'tuesday'করেন 1 2 'monday' 'wednesday'তবে 4 দিন হওয়া উচিত তবে এটি 5
নিক

উত্তর:


5

আপনাকে সপ্তাহের সমস্ত দিনগুলির সাথে emp_idপ্রতিটি দ্বারা প্রতিটি দ্বারা কাজ করা দিনের ছেদগুলি খুঁজে বের করতে taskহবে এবং তারপরে স্বতন্ত্র দিনগুলি গণনা করতে হবে:

with days_num as (
  SELECT *
  FROM (
    VALUES ('monday', 1), ('tuesday', 2), ('wednesday', 3), ('thursday', 4), ('friday', 5)
  ) AS d (day, day_no)
),
emp_day_nums as (
  select emp_id, d1.day_no AS start_day_no, d2.day_no AS end_day_no
  from times t
  join days_num d1 on d1.day = t.start_day
  join days_num d2 on d2.day = t.end_day
)
select emp_id, count(distinct d.day_no) AS distinct_days
from emp_day_nums e
join days_num d on d.day_no between e.start_day_no and e.end_day_no
group by emp_id

আউটপুট:

emp_id  distinct_days
1       4
2       5

এসকিউএলফিডেলে ডেমো


আমার লেখার সময় আমি আপনার উত্তরটি দেখতে পাইনি। এখন আমি দেখতে পাচ্ছি যে আমি প্রয়োজনের চেয়ে জিনিসগুলিকে আরও জটিল করে তুলছি। আমি আপনার সমাধান পছন্দ।
Thorsten Kettner

2
@ThorstenKettner হাঁ - আমি প্রথমে রিকার্সিভ কোটে পথ নিজেকে নিচে শুরু করলেও উপলব্ধি একটি ব্যবহার joinসঙ্গে betweenযেমন শর্ত একই ফলাফল আরো নির্দ্ধিধায় অর্জন ...
নিক

6

প্রশ্নের (বিবরণ) বিবৃতিটি সহজ করার জন্য একটি সম্ভাব্য পন্থাটি হ'ল VALUESটেবিল মান নির্মাতা এবং উপযুক্ত যোগদান করে:

SELECT 
   t.emp_id,
   SUM(CASE 
      WHEN d1.day_no = d2.day_no THEN 1
      ELSE d2.day_no - d1.day_no
   END) AS no_of_days
FROM times t
JOIN (VALUES ('monday', 1), ('tuesday', 2), ('wednesday', 3), ('thursday', 4), ('friday', 5)) d1 (day, day_no) 
   ON t.start_day = d1.day
JOIN (VALUES ('monday', 1), ('tuesday', 2), ('wednesday', 3), ('thursday', 4), ('friday', 5)) d2 (day, day_no) 
   ON t.end_day = d2.day
GROUP BY t.emp_id

তবে আপনি যদি স্বতন্ত্র দিনগুলি গণনা করতে চান তবে বিবৃতিটি আলাদা। আপনাকে সমস্ত দিন start_dayএবং end_dayব্যাপ্তির মধ্যে খুঁজে পেতে এবং স্বতন্ত্র দিনগুলি গণনা করতে হবে:

;WITH daysCTE (day, day_no) AS (
   SELECT 'monday', 1 UNION ALL
   SELECT 'tuesday', 2 UNION ALL
   SELECT 'wednesday', 3 UNION ALL
   SELECT 'thursday', 4 UNION ALL
   SELECT 'friday', 5 
)
SELECT t.emp_id, COUNT(DISTINCT d3.day_no)
FROM times t
JOIN daysCTE d1 ON t.start_day = d1.day
JOIN daysCTE d2 ON t.end_day = d2.day
JOIN daysCTE d3 ON d3.day_no BETWEEN d1.day_no AND d2.day_no
GROUP BY t.emp_id

এই ক্যোয়ারী (ওপিএস মূল ক্যোয়ারির মতো) কাজ করে না, আপনি যদি ফলাফলটিতে পরিবর্তন 1 2 'monday' 'tuesday' করেন 1 2 'monday' 'wednesday' তবে 4 দিন হওয়া উচিত তবে এটি 5 ফিরে আসে
নিক নিক

@ নিক, দুঃখিত, আমি বুঝতে পারি না। Ops ব্যাখ্যা উপর নির্ভর করে, সেখানে মধ্যে 2 দিন mondayএবং wednesday। আমি কিছু অনুপস্থিত করছি?
Zhorov

আমি বর্ণিত হিসাবে ইনপুট ডেটা পরিবর্তন করুন এবং আপনার ক্যোয়ারী ৫ টি প্রত্যাবর্তন করবে তবে উত্তরটি এখনও 4 হওয়া উচিত কারণ এখনও 4 টি অনন্য দিন কাজ করেছে।
নিক

@ নিক, এখন আমি আপনার বিষয়টি বুঝতে পারি তবে আমি যদি ওপিএসের ঝাঁকুনিতে মানগুলি পরিবর্তন করি তবে ফলাফলটি হবে 5, তা নয় 4। এই উত্তরটি আরও সহজ সরল বিবৃতি দেয়। ধন্যবাদ।
Zhorov

ওপিএস কোয়েরিও ভুল is কেবল 4 টি অনন্য দিন রয়েছে বলে সেই ডেটা সহ সঠিক উত্তর 4।
নিক

2

আপনার জিজ্ঞাসাটি সঠিক নয়। বুধবার থেকে বৃহস্পতিবার সহ সোমবার থেকে মঙ্গলবার চেষ্টা করুন। এর ফলাফলটি 4 দিনের মধ্যে হওয়া উচিত তবে আপনার ক্যোয়ারী 2 দিন ফেরত দেয়। আপনার জিজ্ঞাসাটি এমনকি দুটি ব্যাপ্তি সংলগ্ন বা ওভারল্যাপিং কিনা তাও সনাক্ত করে না।

এটির সমাধানের একটি উপায় হ'ল একটি দিন থেকে সমস্ত দিন পেতে একটি পুনরাবৃত্ত সিটিই লিখুন এবং তারপরে স্বতন্ত্র দিন গণনা করুন।

with weekdays (day_name, day_number) as
(
  select * from (values ('monday', 1), ('tuesday', 2), ('wednesday', 3),
                        ('thursday', 4), ('friday', 5)) as t(x,y)
)
, emp_days(emp_id, day, last_day)
as
(
  select emp_id, wds.day_number, wde.day_number
  from times t
  join weekdays wds on wds.day_name = t.start_day
  join weekdays wde on wde.day_name = t.end_day
  union all
  select emp_id, day + 1, last_day
  from emp_days
  where day < last_day
)
select emp_id, count(distinct day)
from emp_days
group by emp_id
order by emp_id;

ডেমো: http://sqlfiddle.com/#!18/4a5ac/16

(যেমন দেখা যায় আমি মান নির্মাতাকে সরাসরি হিসাবে প্রয়োগ করতে পারিনি with weekdays (day_name, day_number) as (values ('monday', 1), ...)why কেন জানি না that তা কি এসকিউএল সার্ভার বা আমার? ভাল, অতিরিক্ত নির্বাচনের সাহায্যে এটি কাজ করে :-)


2
with cte as 
(Select id, start_day as day
   group by id, start_day
 union 
 Select id, end_day as day
   group by id, end_day
)

select id, count(day)
from cte
group by id

3
তারা কীভাবে এবং কেন কাজ করে তার কিছু ব্যাখ্যা যুক্ত করে কেবল উত্তরগুলির কোডগুলি প্রায় সর্বদা উন্নত করা যায়।
জেসন অ্যালার

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

1
declare @times table
(
  emp_id int,
  task_id int,
  start_day varchar(50),
  end_day varchar(50)
);

insert into @times(emp_id, task_id, start_day, end_day)
values
(1, 1, 'monday', 'wednesday'),
(1, 2, 'monday', 'tuesday'),
(1, 3, 'friday', 'friday'),
--
(2, 1, 'monday', 'friday'),
(2, 2, 'tuesday', 'wednesday'),
--
(3, 1, 'monday', 'wednesday'),
(3, 2, 'monday', 'tuesday'),
(3, 3, 'monday', 'tuesday');

--for sql 2019, APPROX_COUNT_DISTINCT() eliminates distinct sort (!!)...
-- ...with a clustered index on emp_id (to eliminate the hashed aggregation) the query cost gets 5 times cheaper ("overlooking" the increase in memory) !!??!!
/*
select t.emp_id, APPROX_COUNT_DISTINCT(v.val) as distinctweekdays
from
(
select *, .........
*/


select t.emp_id, count(distinct v.val) as distinctweekdays
from
(
select *, 
case start_day when 'monday' then 1
      when 'tuesday' then 2
      when 'wednesday' then 3
      when 'thursday' then 4
      when 'friday' then 5
    end as start_day_num,
case end_day when 'monday' then 1
      when 'tuesday' then 2
      when 'wednesday' then 3
      when 'thursday' then 4
      when 'friday' then 5
    end as end_day_num
from @times
) as t
join (values(1),(2), (3), (4), (5)) v(val) on v.val between t.start_day_num and t.end_day_num
group by t.emp_id;

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