PostgreSQL এ দুটি তারিখের মধ্যে সময় সিরিজ তৈরি করা


92

আমার কাছে এই জাতীয় একটি কোয়েরি রয়েছে যা 2 প্রদত্ত তারিখগুলির মধ্যে সুন্দরভাবে তারিখগুলির একটি সিরিজ উত্পন্ন করে:

select date '2004-03-07' + j - i as AllDate 
from generate_series(0, extract(doy from date '2004-03-07')::int - 1) as i,
     generate_series(0, extract(doy from date '2004-08-16')::int - 1) as j

এটা তোলে মধ্যে 162 তারিখ উত্পন্ন 2004-03-07এবং 2004-08-16এবং এই আমি কি চাই। এই কোডটির সাথে সমস্যাটি হ'ল দুটি তারিখটি বিভিন্ন বছর হতে গেলে এটি সঠিক উত্তর দেয় না, উদাহরণস্বরূপ যখন আমি চেষ্টা করি 2007-02-01এবং 2008-04-01

এর চেয়ে ভাল সমাধান কি আছে?


উত্তর:


175

ইন / থেকে ইনটি রূপান্তর ছাড়াই করা যায় (তবে পরিবর্তে / টাইমস্ট্যাম্প থেকে)

SELECT date_trunc('day', dd):: date
FROM generate_series
        ( '2007-02-01'::timestamp 
        , '2008-04-01'::timestamp
        , '1 day'::interval) dd
        ;

4
কেন date_truncদরকার?
Idefixx

4
এটি কেবল উপস্থাপনা। এটি টাইমস্ট্যাম্পের সময়ের অংশের মুদ্রণ সরিয়ে দেয় যা এক্ষেত্রে আলওয়াস জেরো।
বীমতি

73

খেজুরের একটি সিরিজ উত্পন্ন করার জন্য এটি সর্বোত্তম উপায়:

SELECT t.day::date 
FROM   generate_series(timestamp '2004-03-07'
                     , timestamp '2004-08-16'
                     , interval  '1 day') AS t(day);
  • অতিরিক্ত date_trunc()প্রয়োজন হয় না। date( day::date) এ cast ালাই স্পষ্টভাবে তা করে।

  • তবে dateইনপুট প্যারামিটার হিসাবে তারিখের আক্ষরিক কাস্টিংয়ের কোনও অর্থ নেই । অ কনটায়ার, timestampসেরা পছন্দ । পারফরম্যান্সে সুবিধাটি কম, তবে এটি না নেওয়ার কোনও কারণ নেই। আর তুমি অযথা ডিএসটি (দিবালোক সময় সংরক্ষণ) জড়িত না থেকে রুপান্তরের সঙ্গে মিলিত নিয়ম না dateকরতে timestamp with time zoneএবং ফিরে। নিচে দেখ.

সমতুল্য, কম স্বচ্ছ সংক্ষিপ্ত বাক্য গঠন:

SELECT day::date 
FROM   generate_series(timestamp '2004-03-07', '2004-08-16', '1 day') day;

বা তালিকার সেট-রিটার্নিং ফাংশন সহ SELECT:

SELECT generate_series(timestamp '2004-03-07', '2004-08-16', '1 day')::date AS day;

ASশব্দ হয় প্রয়োজনীয় গত বৈকল্পিক এ, Postgres কলাম ওরফে ভুল ব্যাখ্যা হবে dayঅন্যথায়। এবং পোস্টগ্রিস 10 এর আগে আমি সেই বৈকল্পিকটিকে পরামর্শ দেব না - কমপক্ষে একই SELECTতালিকায় একাধিক সেট-রিটার্নিং ফাংশন সহ না :

(একপাশে, শেষ বৈকল্পিক সাধারণত একটি ছোট মার্জিন দ্বারা দ্রুত হয়।)

কেন timestamp [without time zone] ?

এর বেশ কয়েকটি ওভারলোডেড ভেরিয়েন্ট রয়েছে generate_series()। বর্তমানে (পোস্টগ্রিজ ১১):

SELECT oid::regprocedure   AS function_signature
     , prorettype::regtype AS return_type
FROM   pg_proc
where  proname = 'generate_series';
ফাংশন_সাইনচার | রিটার্ন_প্রকার                
: --------------------------------------------------------- ------------------------------- | : --------------------------
জেনারেট_সারিজ (পূর্ণসংখ্যা, পূর্ণসংখ্যা, পূর্ণসংখ্যা) | পূর্ণসংখ্যা                    
জেনারেট_সারিজ (পূর্ণসংখ্যা, পূর্ণসংখ্যা) | পূর্ণসংখ্যা                    
জেনারেট_সরিজ (বিগিন্ট, বিগিন্ট, বিগিন্ট) | বিগিন্ট                     
জেনারেট_সরিজ (বিগিন্ট, বিগিন্ট) | বিগিন্ট                     
জেনারেট_সরিজ (সংখ্যাসূচক, সংখ্যাসূচক, সংখ্যাসূচক) | সংখ্যাযুক্ত                    
জেনারেট_সারিজ (সংখ্যাসূচক, সংখ্যাসূচক) | সংখ্যাযুক্ত                    
জেনারেট_সরিজ (সময় অঞ্চল ছাড়া টাইমস্ট্যাম্প, সময় অঞ্চল ছাড়া টাইমস্ট্যাম্প, ব্যবধান) | টাইম জোন ছাড়াই টাইমস্ট্যাম্প
জেনারেট_সারিজ (টাইম জোন সহ টাইমস্ট্যাম্প, টাইম জোন সহ টাইমস্ট্যাম্প, ইন্টারভাল) | সময় অঞ্চল সঙ্গে টাইমস্ট্যাম্প

( numericরূপগুলো Postgres 9.5 সঙ্গে যোগ করা হয় নি।) প্রাসঙ্গিক বেশী গত দুটি গাঢ় গ্রহণ এবং ফিরে timestamp/ timestamptz

নেই কোন বৈকল্পিক গ্রহণ বা ফিরেdate । ফিরে আসার জন্য একটি স্পষ্ট কাস্ট প্রয়োজন datetimestampআর্গুমেন্টগুলির সাথে কলটি ফাংশন ধরণের রেজোলিউশন বিধিগুলিতে না নেমে এবং ইনপুটটির জন্য অতিরিক্ত castালাই ছাড়াই সেরা রূপটিতে সমাধান হয়।

timestamp '2004-03-07'সম্পূর্ণরূপে বৈধ, বিটিডাব্লু। বাদ দেওয়া সময়ের অংশটি 00:00আইএসও ফর্ম্যাটের সাথে ডিফল্ট ।

ফাংশন ধরণের রেজোলিউশনের জন্য ধন্যবাদ আমরা এখনও পাস করতে পারি date। তবে এর জন্য পোস্টগ্র্রেসের আরও কাজ প্রয়োজন। একটা হল অন্তর্নিহিত ঢালাই থেকে dateথেকে timestampথেকে এক সেইসাথে dateথেকে timestamptz। দ্ব্যর্থক হতে পারে, কিন্তু timestamptzকরা হয় "পছন্দের" "তারিখ / সময় ধরনের" মধ্যে। সুতরাং ম্যাচটি 4 য় ধাপে স্থির হয় :

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

ফাংশন ধরণের রেজোলিউশনে অতিরিক্ত কাজ ছাড়াও এটি একটি অতিরিক্ত addsালাই যুক্ত করে timestamptz- যা কেবলমাত্র আরও বেশি দাম যোগ করে না, এটি ডিএসটি-র সাথে সমস্যাগুলিও চালু করতে পারে যা বিরল ক্ষেত্রে অপ্রত্যাশিত ফলাফলের দিকে পরিচালিত করে। (ডিএসটি একটি মরোনিক ধারণা, বিটিডব্লু, এটি যথেষ্ট চাপ দিতে পারে না)) সম্পর্কিত:

আমি আরও ব্যয়বহুল ক্যোয়ারী প্ল্যান দেখিয়ে ফিডলে ডেমো যুক্ত করেছি:

ডিবি <> ফিডল এখানে

সম্পর্কিত:


7
আরও ছোট সংস্করণ:SELECT generate_series(timestamp '2004-03-07', '2004-08-16', '1 day') :: DATE AS day;
ভ্যাক্লাভ কুয়েল

টি (দিন) সিনট্যাক্সটি কী বোঝায়?
পুনর্নির্মাণ করুন

@ রেন্ডাং: AS t(day)ইন SELECT * FROM func() AS t(day)টেবিল এবং কলামের উপনাম রয়েছে। মূল ASশব্দটি এই প্রসঙ্গে noiseচ্ছিক শব্দ noise দেখুন: স্ট্যাকওভারফ্লো.com
এরউইন ব্র্যান্ডস্টেটার

35

আপনি খেজুরের সাথে সরাসরি সিরিজ তৈরি করতে পারেন। ইনটস বা টাইমস্ট্যাম্পগুলি ব্যবহার করার দরকার নেই:

select date::date 
from generate_series(
  '2004-03-07'::date,
  '2004-08-16'::date,
  '1 day'::interval
) date;

আপনার টাইম জোনের উপর নির্ভর করে এটি একটি অপ্রত্যাশিত ফলাফল দিতে পারে। আমার এই সমস্যা ছিল পরিবর্তে টাইমস্ট্যাম্প ব্যবহার করুন। SET অধিবেশন টাইম জোন 'আমেরিকা / সাওপাওলো' নির্বাচন D :: তারিখ থেকে জেনারেট_সরিজ ('2019-11-01' :: তারিখ, '2019-11-03' :: তারিখ, '1 দিন') d নির্বাচন D :: তারিখ থেকে জেনারেট_সরিজ ('2019-11-01' :: তারিখ, '2019-11-04' :: তারিখ, '1 দিন') d
পালহারে

1

আপনি এটি ব্যবহার করতে পারেন।

select generate_series  ( '2012-12-31'::timestamp , '2018-10-31'::timestamp , '1 day'::interval) :: date 
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.