2011-12-22 17 views
26

मान लें कि मेरे पास शॉपिंग साइट के डेटाबेस में Product तालिका है, जो स्टोर के उत्पादों का विवरण, मूल्य इत्यादि रखने के लिए है। मेरे क्लाइंट को इन उत्पादों को फिर से ऑर्डर करने में सक्षम करने का सबसे प्रभावी तरीका क्या है?डेटाबेस तालिका में सॉर्ट ऑर्डर कॉलम का उपयोग

मैं रिकॉर्ड्स को सॉर्ट करने के लिए उपयोग करने के लिए Order कॉलम (पूर्णांक) बनाता हूं, लेकिन मुझे वास्तव में बदलने की आवश्यकता के बाद प्रत्येक रिकॉर्ड के क्रम को बदलने के लिए उपयोग की जाने वाली आदिम विधियों के कारण प्रदर्शन के संबंध में कुछ सिरदर्द देता है। एक उदाहरण:

Id Order 
5  3 
8  1 
26 2 
32 5 
120 4 

अब मैं क्या करने के लिए 3 ID=26 साथ रिकॉर्ड का क्रम बदलने के कर सकते हैं?

मैंने जो किया वह एक प्रक्रिया तैयार कर रहा था जो जांचता है कि लक्ष्य आदेश (3) में कोई रिकॉर्ड है या नहीं, तो पंक्ति के क्रम (आईडी = 26) को अद्यतन करता है। यदि लक्ष्य आदेश में कोई रिकॉर्ड है तो प्रक्रिया पैरामीटर के रूप में target order + 1 के साथ उस पंक्ति की आईडी भेजकर स्वयं निष्पादित करती है।

एक मैं जगह बनाने के लिए परिवर्तित करना चाहते हैं के बाद हर एक रिकॉर्ड को अपडेट करने का कारण बनता है कि:

Id Order 
5  4 
8  1 
26 3 
32 6 
120 5 

तो क्या एक होशियार व्यक्ति करना होगा?

  • मैं SQL Server 2008 R2 का उपयोग करता हूं।

संपादित करें:

मैं एक आइटम के आदेश स्तंभ की जरूरत है कोई द्वितीयक शामिल कुंजी के साथ छँटाई के लिए पर्याप्त होना चाहिए। ऑर्डर कॉलम को अपने रिकॉर्ड के लिए एक अनूठी जगह निर्दिष्ट करनी होगी।

सभी के अलावा, मुझे आश्चर्य है कि क्या मैं किसी लिंक किए गए सूची की तरह कुछ कार्यान्वित कर सकता हूं: अगली आइटम आईडी रखने के लिए 'ऑर्डर' कॉलम के बजाय 'अगला' कॉलम। लेकिन मुझे नहीं पता कि क्वेरी को कैसे लिखना है जो सही क्रम के साथ रिकॉर्ड पुनर्प्राप्त करता है। अगर किसी को भी इस दृष्टिकोण के बारे में कोई जानकारी है, तो कृपया साझा करें।

+12

एक अधिक अनुभवी व्यक्ति एक स्तंभ 'Order' फोन नहीं होता है कि पहले से ही एसक्यूएल में एक आरक्षित कीवर्ड है, क्योंकि .... :-) –

उत्तर

24
Update product set order = order+1 where order >= @value changed 

हालांकि समय के साथ आप में अधिकाधिक अपने आदेश में "रिक्त स्थान" मिल जाएगा लेकिन यह अभी भी होगा "प्रकार"

यह मान को 1 जोड़ देगा बदल गया है और किया जा रहा से एक में यह बाद हर मूल्य बयान, लेकिन उपरोक्त कथन अभी भी सच है। बड़े और बड़े "रिक्त स्थान" आपके आदेश में संभवतः एक आईएनटी मूल्य से अधिक होने के बिंदु पर पहुंच जाएंगे।

वैकल्पिक समाधान कोई रिक्त स्थान के लिए दिए गए इच्छा: निर्भर करता है, तो नए/पुराने आदेश ऊपर जा रहा है या कर रहा है @NewOrderVal, @ IDToChange, @ OriginalOrderVal

दो चरणों वाली प्रक्रिया के मापदंडों के साथ UpdateSortOrder:

के लिए एक प्रक्रिया की कल्पना तरह नीचे।

If @NewOrderVal < @OriginalOrderVal --Moving down chain 

--Create space for the movement; no point in changing the original 
    Update product set order = order+1 
    where order BETWEEN @NewOrderVal and @OriginalOrderVal-1; 

end if 

If @NewOrderVal > @OriginalOrderVal --Moving up chain 

--Create space for the momvement; no point in changing the original 
    Update product set order = order-1 
    where order between @OriginalOrderVal+1 and @NewOrderVal 
end if 

--Finally update the one we moved to correct value 

    update product set order = @newOrderVal where [email protected]; 

सर्वोत्तम अभ्यास के संबंध में; अधिकांश वातावरण जो मैं आमतौर पर श्रेणी द्वारा समूहित करना चाहता हूं और वर्णानुक्रम में क्रमबद्ध हूं या "बिक्री पर लोकप्रियता" के आधार पर उपयोगकर्ता परिभाषित प्रकार प्रदान करने की आवश्यकता को अस्वीकार करता हूं।

+1

धन्यवाद। यह सही नहीं है हालांकि यह काम करेगा और यह विकास में सबसे महत्वपूर्ण बात है। लेकिन मैं इस स्थिति के लिए 'सर्वोत्तम अभ्यास' की तरह कुछ की उम्मीद कर रहा था। मुझे इसे अक्सर आवश्यकता होती है और हर बार विभिन्न तरीकों से आती है। यह मेरे लिए आश्चर्य की बात है कि कोई भी ज्ञात तरीका नहीं है जिसे हर कोई जानता है और उपयोग करता है। –

+0

अच्छी तरह से आप उपयोगकर्ता को "डोन" बटन पर क्लिक कर सकते हैं जो "आदेश" – xQbert

+0

द्वारा क्रमबद्ध क्वेरी पर आधारित "ऑर्डर" फ़ील्ड = राउनम सेट का उपयोग करेगा, वास्तव में एक अच्छा समाधान। धन्यवाद। मेरे पास एक और सवाल है हालांकि: आपने अपने दूसरे उदाहरण में बदलने के लिए आवश्यक एक को अपडेट करने से पहले रिकॉर्ड को अपडेट किया है। इसका मतलब है कि एक पल के लिए एक ही ऑर्डर वैल्यू साझा करने वाली दो पंक्तियां होंगी। अगर मैं ऑर्डर कॉलम पर अनन्य बाधा डालता हूं तो मैं ऐसा कैसे कर सकता हूं? –

4

एक समाधान मैंने अतीत में उपयोग किया है, कुछ सफलता के साथ, 'ऑर्डर' के बजाय 'वजन' का उपयोग करना है। वजन स्पष्ट है, भारी वस्तु (यानी: संख्या कम) नीचे की ओर डूब जाती है, हल्का (उच्च संख्या) शीर्ष पर उगता है।

यदि मेरे पास एक ही वजन के साथ कई आइटम हैं, तो मुझे लगता है कि वे एक ही महत्व के हैं और मैं उन्हें वर्णानुक्रम से आदेश देता हूं।

ORDER BY 'weight', 'itemName' 

आशा व्यक्त की कि मदद करता है:

अपने एसक्यूएल कुछ इस तरह दिखेगा इसका मतलब यह है।

+0

धन्यवाद। यह एक समाधान है लेकिन यह मेरी वर्तमान विधि से अलग नहीं है। यह मेरी गलती है हालांकि मुझे यह निर्दिष्ट करना चाहिए था कि मुझे ऑर्डर कॉलम को अद्वितीय होने की आवश्यकता है। (मैं तुरंत प्रश्न को अपडेट कर दूंगा) मुझे क्लाइंट को यह तय करने में सक्षम होना चाहिए कि कौन सा आइटम पहले आता है। मेरे पास नाम की तरह द्वितीयक स्थिति नहीं है, इस मामले में आदेश पर्याप्त होना चाहिए। यदि मेरे पास 10 और 11 भारित दो आइटम हैं, तो मैं उनके वजन को बदलने के बिना उनके बीच एक रिकॉर्ड कैसे दिखा सकता हूं (और इसके परिणामस्वरूप उनके बाद के वजन) मेरा वास्तविक प्रश्न था। –

+0

क्या ऑर्डर अद्वितीय-साथ-न-अंतराल होना चाहिए? यदि हां, तो क्यों? उल्लिखित तकनीक पूरी तरह से कॉलम पर एक अद्वितीय बाधा हो सकती है, इसलिए ऑर्डर अद्वितीय है। –

+0

क्षमा करें, मुझे यह नहीं मिला। अंतराल समस्या नहीं है। मुझे समझ में नहीं आता कि क्या होने जा रहा है जब दो वस्तुओं का वही वज़न होता है या मैं 10 और 11 भारित दो रिकॉर्ड के बीच रिकॉर्ड कैसे बना सकता हूं (जैसा कि मैंने अपनी पिछली टिप्पणी में उल्लेख किया है)। विशेष रूप से अगर मेरे पास कॉलम पर एक अनोखी बाधा है। मुझे उस मामले में अन्य वस्तुओं के वजन में से एक को बदलना होगा। क्या आप सुझाव दे रहे हैं कि मुझे 1 से वजन कम नहीं करना चाहिए? मैं क्षमा चाहता हूं अगर मुझे कुछ स्पष्ट याद आ रही है। –

5

पुरानी चाल का उपयोग करें जो बेसिक प्रोग्राम (अन्य स्थानों के साथ) का उपयोग किया जाता है: क्रमशः कॉलम में संख्याओं को 10 या कुछ अन्य सुविधाजनक वृद्धि से कूदें। फिर आप दो मौजूदा संख्याओं (जो कि 10 अलग हैं) के बीच एक पंक्ति (वास्तव में, 9 पंक्तियों तक, यदि आप भाग्यशाली हैं) डाल सकते हैं। या आप 570 ऊपर से किसी भी पंक्ति को बदलने के बिना पंक्ति 370 से 565 तक जा सकते हैं।

1

(अंग्रेजी के लिए खेद। मैं अध्ययन कर रहा हूँ)

wery सरल है। आप "प्रमुखता छेद"

संरचना आप 2 स्तंभ

1) पी = 32 बिट पूर्णांक

2) आदेश = 64 बिट bigint (BIGINT, डबल नहीं है की जरूरत है की जरूरत है !!!)

1) जब आप पहले नए रिकॉर्ड डालते हैं तो आपको ऑर्डर = राउंड (max_bigint/2) सेट करना होगा।

2) यदि आप तालिका आप सेट करना होगा की शुरुआत में सम्मिलित = दौर ("पहले रिकॉर्ड के आदेश"/2)

3) यदि आप तालिका के अंत में सम्मिलित आप सेट करना होगा = दौर ("max_bigint - पिछले रिकॉर्ड के आदेश"/2)

4) यदि आप बीच में डालने आप = क्रम सेट करना होगा दौर ("से पहले रिकॉर्ड के आदेश - के बाद रिकॉर्ड के आदेश"/2)

इस विधि बहुत बड़ी कार्डिटिलिटी है। यदि आपके पास बाधा त्रुटि है या यदि आपको लगता है कि आपके पास छोटी कार्डिनालिटी है तो आप ऑर्डर कॉलम (सामान्यीकृत) का पुनर्निर्माण कर सकते हैं।

सामान्यीकरण (इस संरचना के साथ) के साथ अधिकतमता स्थिति में आप 32 बिट में "कार्डिनालिटी होल" प्राप्त कर सकते हैं।

बहुत आसान और तेज़ है!

कोई दोगुना याद नहीं है !!! केवल आईएनटी - ऑर्डर सटीक मूल्य है!

+0

@ एंडीएम: यह एक नया सवाल नहीं है, यह दिए गए प्रश्न – cfi

+0

ओई का उत्तर देने का प्रयास है, मैंने इसे गलत समझा, मेरा बुरा! –

+3

लेकिन केवल 64 डालने वाली पंक्तियों के बाद आप "ऑर्डर" के लिए मानों से बाहर हो जाएंगे (ऑर्डर वैल्यू 1 से कम होगा) –

1

मैं वर्तमान में एक पेड़ संरचना के साथ एक डेटाबेस विकसित कर रहा हूं जिसे आदेश देने की आवश्यकता है। मैं एक लिंक-सूची प्रकार की विधि का उपयोग करता हूं जिसे क्लाइंट (डेटाबेस नहीं) पर आदेश दिया जाएगा। एक रिकर्सिव क्वेरी के माध्यम से डेटाबेस में ऑर्डरिंग भी किया जा सकता है, लेकिन यह इस परियोजना के लिए आवश्यक नहीं है।

मैंने यह दस्तावेज़ बनाया है जो वर्णन करता है कि हम कैसे क्रमबद्ध क्रम के भंडारण को लागू करने जा रहे हैं, जिसमें postgresql में एक उदाहरण शामिल है। टिप्पणी करने के लिए स्वतंत्र हैं!

https://docs.google.com/document/d/14WuVyGk6ffYyrTzuypY38aIXZIs8H-HbA81st-syFFI/edit?usp=sharing

+0

+1, अच्छा नमूना। मेरे पास दो प्रश्न हैं: ** पहला: ** आपके पास 'माता-पिता' और 'आगे बढ़ने' दोनों क्यों हैं - एक लिंक की गई सूची के बजाय डबल लिंक्ड सूची क्यों? ** दूसरा: ** आप आदेशित रिकॉर्ड का चयन कैसे करते हैं: उदाहरण के लिए, अपने माता-पिता/बच्चे संबंधों द्वारा आदेशित पहले 100 रिकॉर्ड का चयन करें। –

+0

माता-पिता एक वृक्ष संरचना में पैरेंट नोड को संदर्भित करता है। पिछला कॉलम नोड्स के क्रम को परिभाषित करता है। मैंने हाल ही में एक चयन के साथ दस्तावेज़ में उदाहरण अपडेट किया है जो एक रिकर्सिव सामान्य तालिका अभिव्यक्ति के माध्यम से अपने सही क्रम में नोड्स प्राप्त करता है। – Elmer

2

यहां एक सामान्य तालिका अभिव्यक्ति (CTE) का उपयोग करते हुए एक वैकल्पिक दृष्टिकोण है।

यह दृष्टिकोण सॉर्टऑर्डर कॉलम पर एक अद्वितीय इंडेक्स का सम्मान करता है, और सॉर्ट ऑर्डर अनुक्रम में किसी भी अंतराल को बंद कर देगा जो पहले DELETE संचालन से छोड़ा गया हो सकता है।

/* For example, move Product with id = 26 into position 3 */ 
DECLARE @id int = 26 
DECLARE @sortOrder int = 3 


;WITH Sorted AS (
    SELECT Id, 
      ROW_NUMBER() OVER (ORDER BY SortOrder) AS RowNumber 
    FROM Product 
    WHERE Id <> @id 
) 

UPDATE p 
SET  p.SortOrder = 
     (CASE 
      WHEN p.Id = @id THEN @sortOrder 
      WHEN s.RowNumber >= @sortOrder THEN s.RowNumber + 1 
      ELSE s.RowNumber 
     END) 
FROM Product p 
     LEFT JOIN Sorted s ON p.Id = s.Id 
संबंधित मुद्दे