PostgreSQL अंतर्निहित दिनांक और समय से संबंधित डेटा प्रकारों के एक समूह के साथ आता है। आपको उनका उपयोग स्ट्रिंग्स या पूर्णांकों पर क्यों करना चाहिए? इनका प्रयोग करते समय आपको किन बातों का ध्यान रखना चाहिए? Postgres में इन डेटाटाइप के साथ प्रभावी ढंग से काम करने के तरीके के बारे में अधिक जानने के लिए पढ़ें।
पूरे प्रकार के ढेर
एसक्यूएल मानक, आईएसओ 8601 मानक, पोस्टग्रेएसक्यूएल की अंतर्निर्मित कैटलॉग और पिछड़ी संगतता एक साथ ओवरलैपिंग, अनुकूलन योग्य दिनांक/समय से संबंधित डेटा प्रकारों और सम्मेलनों की एक बड़ी संख्या को परिभाषित करती है जो सर्वोत्तम रूप से भ्रमित होती है। यह भ्रम आमतौर पर डेटाबेस ड्राइवर कोड, एप्लिकेशन कोड, SQL रूटीन में फैल जाता है और इसके परिणामस्वरूप सूक्ष्म बग होते हैं जिन्हें डीबग करना मुश्किल होता है।
दूसरी ओर, देशी बिल्ट-इन प्रकारों का उपयोग करना SQL कथनों को सरल बनाता है और उन्हें पढ़ने और लिखने में अधिक आसान बनाता है, और परिणामस्वरूप, कम त्रुटि-प्रवण। समय का प्रतिनिधित्व करने के लिए पूर्णांक (युग से सेकंड की संख्या) का उपयोग करना, परिणामी SQL अभिव्यक्तियों में परिणाम देता है और अधिक एप्लिकेशन कोड।
देशी प्रकारों के लाभ गैर-दर्दनाक नियमों के एक सेट को परिभाषित करने और उन्हें पूरे एप्लिकेशन और ऑप्स कोड बेस में लागू करने के लिए सार्थक बनाते हैं। यहां एक ऐसा सेट है, जो आवश्यक होने पर आगे के अनुकूलन के लिए समझदार चूक और एक अनुकूल शुरुआती बिंदु प्रदान करना चाहिए।
प्रकार
केवल निम्नलिखित 3 प्रकारों का उपयोग करें (हालांकि कई उपलब्ध हैं):
- तारीख - एक विशिष्ट तिथि, बिना समय के
- टाइमस्टैम्प्ट्ज - माइक्रोसेकंड रिज़ॉल्यूशन के साथ एक विशिष्ट तिथि और समय
- अंतराल - माइक्रोसेकंड रिज़ॉल्यूशन वाला समय अंतराल
इन तीन प्रकारों को एक साथ अधिकांश अनुप्रयोग उपयोग मामलों का समर्थन करना चाहिए। यदि आपके पास विशिष्ट आवश्यकताएं नहीं हैं (जैसे भंडारण को संरक्षित करना), तो केवल इन प्रकारों से चिपके रहने की अत्यधिक अनुशंसा की जाती है।
तारीख समय के बिना एक तारीख का प्रतिनिधित्व करता है, और व्यवहार में काफी उपयोगी है (नीचे उदाहरण देखें)। टाइमस्टैम्प प्रकार एक प्रकार है जिसमें समय क्षेत्र की जानकारी शामिल होती है - समय क्षेत्र की जानकारी के बिना बहुत अधिक चर होते हैं जो मूल्य की व्याख्या और निष्कर्षण को प्रभावित कर सकते हैं। अंत में, अंतराल माइक्रोसेकंड से लेकर लाखों वर्षों तक के न्यूनतम समय अंतराल को दर्शाता है।
शाब्दिक तार
केवल निम्नलिखित शाब्दिक अभ्यावेदन का उपयोग करें, और पठनीयता का त्याग किए बिना वाचालता को कम करने के लिए कास्ट ऑपरेटर का उपयोग करें:
'2012-12-25'::date
- आईएसओ 8601'2012-12-25 13:04:05.123-08:00'::timestamptz
- आईएसओ 8601'1 month 3 days'::interval
- अंतराल इनपुट के लिए पारंपरिक प्रारूप को पोस्टग्रेज करता है
समय क्षेत्र को छोड़ना आपको पोस्टग्रेज सर्वर की टाइमज़ोन सेटिंग की दया पर छोड़ देता है, टाइमज़ोन कॉन्फ़िगरेशन जिसे डेटाबेस-स्तर, सत्र-स्तर, भूमिका-स्तर या कनेक्शन स्ट्रिंग में सेट किया जा सकता है, क्लाइंट मशीन की टाइमज़ोन सेटिंग, और ऐसे और भी कारक।
एप्लिकेशन कोड से क्वेरी करते समय, extract
का उपयोग करके अंतराल प्रकारों को एक उपयुक्त इकाई (जैसे दिन या सेकंड) में बदलें फ़ंक्शन और मान में पूर्णांक या वास्तविक मान के रूप में पढ़ें।
कॉन्फ़िगरेशन और अन्य सेटिंग
- GUC कॉन्फ़िगरेशन के लिए डिफ़ॉल्ट सेटिंग न बदलें
DateStyle
,TimeZone
औरlc_time
। - पर्यावरण चर सेट या उपयोग न करें
PGDATESTYLE
औरPGTZ
। SET [SESSION|LOCAL] TIME ZONE ...
का इस्तेमाल न करें ।- यदि आप कर सकते हैं, तो सिस्टम टाइमज़ोन को उस मशीन पर यूटीसी पर सेट करें जो पोस्टग्रेस सर्वर चलाती है, साथ ही साथ सभी मशीनें जो एप्लिकेशन कोड चलाती हैं जो इससे जुड़ती हैं।
- मान्य करें कि आपका डेटाबेस ड्राइवर (जैसे JDBC कनेक्टर, या Godatabase/sql ड्राइवर) समझदारी से व्यवहार करता है, जबकि क्लाइंट ऑनटाइमज़ोन पर चल रहा है और सर्वर दूसरे पर चल रहा है। सुनिश्चित करें कि यह सही ढंग से काम करता है जब एक वैध गैर-यूटीसी
TimeZone
पैरामीटर कनेक्शन स्ट्रिंग में शामिल है।
अंत में, ध्यान दें कि ये सभी केवल दिशा-निर्देश हैं और आपकी आवश्यकताओं के अनुरूप इनमें बदलाव किया जा सकता है - लेकिन सुनिश्चित करें कि आप पहले ऐसा करने के निहितार्थों की जांच कर लें।
मूल प्रकार और ऑपरेटर
तो मूल प्रकार का उपयोग वास्तव में SQL कोड को सरल बनाने में कैसे मदद करता है? यहां कुछ उदाहरण दिए गए हैं।
दिनांक प्रकार
तारीख . के मान अंतराल . देने के लिए प्रकार घटाया जा सकता है उन दोनों के बीच। आप किसी पार्टिकुलेट दिनांक में दिनों की पूर्णांक संख्या भी जोड़ सकते हैं, या टाइमस्टैम्प्टज़ देने के लिए दिनांक में अंतराल जोड़ सकते हैं :
-- 10 days from now (outputs 2020-07-26)
SELECT now()::date + 10;
-- 10 days from now (outputs 2020-07-26 04:44:30.568847+00)
SELECT now() + '10 days'::interval;
-- days till christmas (outputs 161 days 14:06:26.759466)
SELECT '2020-12-25'::date - now();
-- the 10 longest courses
SELECT name, end_date - start_date AS duration
FROM courses
ORDER BY end_date - start_date DESC
LIMIT 10;
इन प्रकारों के मान तुलनीय हैं, यही वजह है कि आप end_date - start_date
तक अंतिम क्वेरी का आदेश दे सकते हैं , जिसमें एक प्रकार का अंतराल . होता है . यहां एक और उदाहरण दिया गया है:
-- certificates expiring within the next 7 days
SELECT name
FROM certificates
WHERE expiry_date BETWEEN now() AND now() + '7 days'::interval;
टाइमस्टैम्प प्रकार
timestamptz . प्रकार के मान घटाया भी जा सकता है (अंतराल देने के लिए) ),जोड़ा गया (एक अंतराल . के लिए) एक और timestamptz देने के लिए ) और तुलना की।
-- difference of timestamps gives an interval
SELECT password_last_modified - created_at AS password_age
FROM users;
-- can also use the age() function
SELECT age(password_last_modified, created_at) AS password_age
FROM users;
विषय पर रहते हुए, ध्यान दें कि 3 अलग-अलग अंतर्निहित फ़ंक्शन हैं जो विभिन्न "वर्तमान टाइमस्टैम्प" मान लौटाते हैं। वे वास्तव में अलग-अलग चीजें लौटाते हैं:
-- transaction_timestamp() returns the timestampsz of the start of current transaction
-- outputs 2020-07-16 05:09:32.677409+00
SELECT transaction_timestamp();
-- statement_timestamp() returns the timestamptz of the start of the current statement
SELECT statement_timestamp();
-- clock_timestamp() returns the timestamptz of the system clock
SELECT clock_timestamp();
इन कार्यों के लिए उपनाम भी हैं:
-- now() actually returns the start of the current transaction, which means it
-- does not change during the transaction
SELECT now(), transaction_timestamp();
-- transaction timestamp is also returned by these keyword-style constructs
SELECT CURRENT_DATE, CURRENT_TIMESTAMP, transaction_timestamp();
अंतराल प्रकार
अंतराल-टाइप किए गए मानों का उपयोग कॉलम डेटा प्रकारों के रूप में किया जा सकता है, एक दूसरे के साथ तुलना की जा सकती है और टाइमस्टैम्प और तिथियों में जोड़ा जा सकता है (और घटाया जा सकता है)। यहां कुछ उदाहरण दिए गए हैं:
-- interval-typed values can be stored and compared
SELECT num
FROM passports
WHERE valid_for > '10 years'::interval
ORDER BY valid_for DESC;
-- you can multiply them by numbers (outputs 4 years)
SELECT 4 * '1 year'::interval;
-- you can divide them by numbers (outputs 3 mons)
SELECT '1 year'::interval / 4;
-- you can add and subtract them (outputs 1 year 1 mon 6 days)
SELECT '1 year'::interval + '1.2 months'::interval;
अदर फंक्शंस और कंस्ट्रक्शंस
PostgreSQL भी कुछ उपयोगी कार्यों और संरचनाओं के साथ आता है जिनका उपयोग इस प्रकार के मूल्यों में हेरफेर करने के लिए किया जा सकता है।
निकालें
एक्स्ट्रेक्ट फ़ंक्शन का उपयोग दिए गए मान से एक निर्दिष्ट भाग को पुनः प्राप्त करने के लिए किया जा सकता है, जैसे कि किसी तारीख से महीना। निकाले जा सकने वाले भागों की पूरी सूची यहाँ प्रलेखित है। यहाँ कुछ उपयोगी और गैर-स्पष्ट उदाहरण दिए गए हैं:
-- years from an interval (outputs 2)
SELECT extract(YEARS FROM '1.5 years 6 months'::interval);
-- day of the week (0=Sun .. 6=Sat) from timestamp (outputs 4)
SELECT extract(DOW FROM now());
-- day of the week (1=Mon .. 7=Sun) from timestamp (outputs 4)
SELECT extract(ISODOW FROM now());
-- convert interval to seconds (outputs 86400)
SELECT extract(EPOCH FROM '1 day'::interval);
अंतिम उदाहरण अनुप्रयोगों द्वारा चलाए जा रहे प्रश्नों में विशेष रूप से उपयोगी है, क्योंकि अनुप्रयोगों के लिए सेकंड/मिनट/दिन/आदि की संख्या के फ़्लोटिंग-पॉइंट मान के रूप में अंतराल को संभालना आसान हो सकता है।
समय क्षेत्र रूपांतरण
timestamptz . को व्यक्त करने के लिए एक आसान कार्य भी है किसी अन्य समय क्षेत्र में। आमतौर पर यह एप्लिकेशन कोड में किया जाएगा - इस तरह से परीक्षण करना आसान है, और समय क्षेत्र डेटाबेस पर निर्भरता को कम करता है जिसे पोस्टग्रेसर संदर्भित करेगा। फिर भी, यह कई बार उपयोगी हो सकता है:
-- convert timestamps to a different time zone
SELECT timezone('Europe/Helsinki', now());
-- same as before, but this one is a SQL standard
SELECT now() AT TIME ZONE 'Europe/Helsinki';
टेक्स्ट में और से कनवर्ट करना
फंक्शन to_char
(दस्तावेज़) प्रारूप स्ट्रिंग के आधार पर दिनांक, टाइमस्टैम्प और अंतराल को टेक्स्ट में परिवर्तित कर सकते हैं-क्लासिक सी फ़ंक्शन strftime
के समकक्ष पोस्टग्रेज ।
-- outputs Thu, 16th July
SELECT to_char(now(), 'Dy, DDth Month');
-- outputs 01 06 00 12 00 00
SELECT to_char('1.5 years'::interval, 'YY MM DD HH MI SS');
टेक्स्ट से तारीख में कनवर्ट करने के लिए to_date
. का उपयोग करें , और टेक्स्ट को टाइमस्टैम्प में बदलने के लिए to_timestamp
. का उपयोग करें . ध्यान दें कि यदि आप इस पोस्ट की शुरुआत में सूचीबद्ध प्रपत्रों का उपयोग करते हैं, तो आप इसके बजाय केवल कास्ट ऑपरेटरों का उपयोग कर सकते हैं।
-- outputs 2000-12-25 15:42:50+00
SELECT to_timestamp('2000.12.25.15.42.50', 'YYYY.MM.DD.HH24.MI.SS');
-- outputs 2000-12-25
SELECT to_date('2000.12.25.15.42.50', 'YYYY.MM.DD');
प्रारूप स्ट्रिंग पैटर्न की पूरी सूची के लिए दस्तावेज़ देखें।
साधारण मामलों के लिए इन कार्यों का उपयोग करना सबसे अच्छा है। अधिक जटिल पार्सिंग या स्वरूपण के लिए, एप्लिकेशन कोड पर भरोसा करना बेहतर है, जो (यकीनन) बेहतर इकाई-परीक्षण हो सकता है।
एप्लिकेशन कोड के साथ इंटरफ़ेस करना
कभी-कभी एप्लिकेशन कोड से दिनांक/टाइमस्टैम्प्ज़/अंतराल मानों को पास करना सुविधाजनक नहीं होता है, खासकर जब बाध्य पैरामीटर का उपयोग किया जाता है। उदाहरण के लिए, आमतौर पर अंतराल को एक स्ट्रिंग प्रारूप के बजाय दिनों (या घंटे, या मिनट) की पूर्णांक संख्या के रूप में पारित करना अधिक सुविधाजनक होता है। अंतराल में दिनों (या घंटे, या मिनट आदि) की पूर्णांक/अस्थायी-बिंदु संख्या के रूप में पढ़ना भी आसान है।
make_interval
फ़ंक्शन का उपयोग घटक मानों की एक अभिन्न संख्या से अंतराल मान बनाने के लिए किया जा सकता है (यहां दस्तावेज़ देखें)। to_timestamp
फ़ंक्शन जो हमने पहले देखा था उसका एक और रूप है जो यूनिक्स युग के समय से atimestamptz मान बना सकता है।
-- pass the interval as number of days from the application code
SELECT name FROM courses WHERE duration <= make_interval(days => $1);
-- pass timestamptz as unix epoch (number of seconds from 1-Jan-1970)
SELECT id FROM events WHERE logged_at >= to_timestamp($1);
-- return interval as number of days (with a fractional part)
SELECT extract(EPOCH FROM duration) / 60 / 60 / 24;