वर्तमान में स्वीकृत उत्तर प्रश्न का उत्तर नहीं देता है। और यह सिद्धांत रूप में गलत है। a BETWEEN x AND y
में अनुवाद करता है:
a >= x AND a <= y
सहित ऊपरी सीमा, जबकि लोगों को आमतौर पर बहिष्कृत . की आवश्यकता होती है यह:
a >= x AND a < y
तारीखों के साथ आप आसानी से समायोजित कर सकते हैं। वर्ष 2009 के लिए '2009-12-31' को ऊपरी सीमा के रूप में उपयोग करें।
लेकिन यह टाइमस्टैम्प के साथ उतना आसान नहीं है। जो भिन्नात्मक अंकों की अनुमति देता है। आधुनिक पोस्टग्रेज संस्करण आंतरिक रूप से एक 8-बाइट पूर्णांक का उपयोग 6 भिन्नात्मक सेकंड (µs रिज़ॉल्यूशन) तक संग्रहीत करने के लिए करते हैं। यह जानकर हम कर सकते थे अभी भी इसे काम करते हैं, लेकिन यह सहज नहीं है और कार्यान्वयन विवरण पर निर्भर करता है। बुरा विचार।
इसके अलावा, a BETWEEN x AND y
ओवरलैपिंग रेंज नहीं ढूंढता है। हमें चाहिए:
b >= x AND a < y
और ऐसे खिलाड़ी जिन्होंने कभी नहीं छोड़ा अभी तक विचार नहीं किया गया है।
उचित उत्तर
वर्ष मानते हुए 2009
, मैं इसका अर्थ बदले बिना प्रश्न को फिर से लिखूंगा:
"किसी दी गई टीम के सभी खिलाड़ियों को खोजें जो 2010 से पहले शामिल हुए और 2009 से पहले नहीं गए।"
मूल प्रश्न:
SELECT p.*
FROM team t
JOIN contract c USING (name_team)
JOIN player p USING (name_player)
WHERE t.name_team = ?
AND c.date_join < date '2010-01-01'
AND c.date_leave >= date '2009-01-01';
लेकिन और भी है:
यदि FK बाधाओं के साथ संदर्भात्मक अखंडता को लागू किया जाता है, तो तालिका team
क्वेरी में केवल शोर है और इसे हटाया जा सकता है।
जबकि वही खिलाड़ी एक ही टीम को छोड़ सकता है और फिर से जुड़ सकता है, हमें संभावित डुप्लिकेट को भी मोड़ना होगा, उदाहरण के लिए DISTINCT
के साथ ।
और हम हो सकता है एक विशेष मामले के लिए प्रदान करने की आवश्यकता है:ऐसे खिलाड़ी जिन्होंने कभी नहीं छोड़ा। मान लें कि उन खिलाड़ियों के पास date_leave
. में NULL है ।
"एक खिलाड़ी जिसके बारे में पता नहीं है कि वह चला गया है, उसे आज तक टीम के लिए खेल रहा माना जाता है।"
परिष्कृत क्वेरी:
SELECT DISTINCT p.*
FROM contract c
JOIN player p USING (name_player)
WHERE c.name_team = ?
AND c.date_join < date '2010-01-01'
AND (c.date_leave >= date '2009-01-01' OR c.date_leave IS NULL);
ऑपरेटर वरीयता हमारे खिलाफ काम करती है, AND
OR
. से पहले बाइंड करता है . हमें कोष्ठक चाहिए।
अनुकूलित के साथ संबंधित उत्तर DISTINCT
(यदि डुप्लीकेट आम हैं):
- अनेक से अनेक टेबल - प्रदर्शन खराब है
आमतौर पर, नाम प्राकृतिक व्यक्तियों की संख्या अद्वितीय नहीं है और एक सरोगेट प्राथमिक कुंजी का उपयोग किया जाता है। लेकिन, जाहिर है, name_player
player
. की प्राथमिक कुंजी है . अगर आपको केवल खिलाड़ियों के नाम चाहिए तो हमें टेबल की जरूरत नहीं है player
क्वेरी में, या तो:
SELECT DISTINCT name_player
FROM contract
WHERE name_team = ?
AND date_join < date '2010-01-01'
AND (date_leave >= date '2009-01-01' OR date_leave IS NULL);
एसक्यूएल OVERLAPS
ऑपरेटर
मैनुअल:
<ब्लॉकक्वॉट>
OVERLAPS
स्वचालित रूप से जोड़ी के पहले मान को प्रारंभ के रूप में लेता है। प्रत्येक समयावधि को अर्ध-खुले अंतराल start <= time < end
. का प्रतिनिधित्व करने के लिए माना जाता है , जब तक start
और end
बराबर हैं जिस स्थिति में यह उस एकल समय को तत्काल दर्शाता है।
संभावित NULL
. का ध्यान रखने के लिए मान, COALESCE
सबसे आसान लगता है:
SELECT DISTINCT name_player
FROM contract
WHERE name_team = ?
AND (date_join, COALESCE(date_leave, CURRENT_DATE)) OVERLAPS
(date '2009-01-01', date '2010-01-01'); -- upper bound excluded
इंडेक्स सपोर्ट के साथ रेंज टाइप
पोस्टग्रेज में 9.2 या बाद के संस्करण आप वास्तविक श्रेणी प्रकारों . के साथ भी काम कर सकते हैं :
SELECT DISTINCT name_player
FROM contract
WHERE name_team = ?
AND daterange(date_join, date_leave) &&
daterange '[2009-01-01,2010-01-01)'; -- upper bound excluded
रेंज प्रकार कुछ ओवरहेड जोड़ते हैं और अधिक स्थान घेरते हैं। 2 x date
=8 बाइट्स; 1 एक्स daterange
=डिस्क पर 14 बाइट्स या रैम में 17 बाइट्स। लेकिन ओवरलैप ऑपरेटर &&
. के संयोजन में क्वेरी को जीआईएसटी इंडेक्स के साथ समर्थित किया जा सकता है।
साथ ही, NULL मानों को विशेष-केस करने की कोई आवश्यकता नहीं है। NULL का अर्थ है "ओपन रेंज" एक श्रेणी प्रकार में - ठीक वही जो हमें चाहिए। तालिका परिभाषा को बदलने की भी आवश्यकता नहीं है:हम मक्खी पर श्रेणी प्रकार बना सकते हैं - और मिलान अभिव्यक्ति सूचकांक के साथ क्वेरी का समर्थन कर सकते हैं:
CREATE INDEX mv_stock_dr_idx ON mv_stock USING gist (daterange(date_join, date_leave));
संबंधित:
- औसत स्टॉक इतिहास तालिका