2009-04-14 11 views
16

मेरे पास एक तालिका है जिसमें प्रदर्शन पंक्ति (1-20) के लिए प्रत्येक संख्या के साथ 20 पंक्तियां होती हैं।एक या बहुत कम प्रश्नों में एकाधिक MySQL पंक्तियों का प्रदर्शन क्रम अद्यतन करना

SELECT * FROM `mytable` ORDER BY `display_order` DESC; 

एक व्यवस्थापक क्षेत्र से आप पंक्तियों को खींच सकते हैं या प्रत्येक पंक्ति के लिए मैन्युअल रूप से एक नया नंबर टाइप कर सकते हैं।

निश्चित रूप से प्रत्येक पंक्ति के लिए एक अद्यतन क्वेरी पर लूप के लिए अच्छा नहीं है, 20 पंक्तियों में या उससे भी अधिक, 50-200 + में एक सेल को अपडेट करने के लिए उपयुक्त एक या बहुत कम प्रश्नों में एक विकल्प क्या है?


संपादित करें: अच्छा प्रतिक्रियाओं और विचारों का एक बहुत। मैं विचारों मैं अब तक माना जाता है पर विस्तार हो सकता है:

एक सरणी स्ट्रिंग: मैं आदेश मैं चाहता हूँ में अद्वितीय पंक्ति आईडी लिस्टिंग एक स्ट्रिंग में आदेश हो सकता है - जैसे पंक्तियों 1,9,2, 6,23। जब आदेश अद्यतन किया जाता है, जावास्क्रिप्ट के साथ एक छिपी हुई फ़ील्ड अद्यतन और कहते हैं कि जब पूरा डेटाबेस या किसी पाठ फ़ाइल में:

UPDATE `my_dispaly_order_table` SET `display_order`='1,9,2,6,23'; 

अद्यतन प्रत्येक पंक्ति को व्यक्तिगत रूप से: यह है कि मैं क्या से बचने के लिए कोशिश कर रहा था, लेकिन यह होता है शायद ही कभी बदला जा तो एक हिट में 20-30 कॉल एक बार एक सप्ताह या महीने में एक समस्या नहीं हो सकता तो बस फोन कर प्रत्येक पंक्ति पर अद्यतन क्या मैं आमतौर पर करते हैं:

UPDATE `mytable` SET `display_order`='1' WHERE `rowId` = 1; 
UPDATE `mytable` SET `display_order`='2' WHERE `rowId` = 9; 
UPDATE `mytable` SET `display_order`='3' WHERE `rowId` = 2; 
UPDATE `mytable` SET `display_order`='4' WHERE `rowId` = 6; 
UPDATE `mytable` SET `display_order`='5' WHERE `rowId` = 23; 
+0

इस एक लिंक्ड सूची समस्या है। शायद एक स्कीमा परिवर्तन का तात्पर्य है। – Randy

उत्तर

0

आप अस्थायी तालिका बना सकते हैं और उन पंक्तियों की प्राथमिक कुंजी के साथ पॉप्युलेट करें जिन्हें आप बदलना चाहते हैं, और display_order के नए मानों के लिए उन पंक्तियों, फिर एक बार में तालिका को अद्यतन करने के लिए अद्यतन के बहु-तालिका संस्करण का उपयोग करें। मैं यह नहीं मानूंगा कि यह तेज़ है, हालांकि, दोनों दृष्टिकोणों के परीक्षण के बिना नहीं।

0

तालिका में एक आईडी (या अन्य कुंजी) जोड़ें, और बदली पंक्ति के आईडी (या कुंजी) = आईडी (या कुंजी) को अपडेट करें।

बेशक, आपको यह सुनिश्चित करना होगा कि या तो कोई डुप्लिकेट display_order मान नहीं है, या आप किसी भी क्रम में प्रदर्शित प्रदर्शन_ऑर्डर में संबंधों के साथ ठीक हैं, या आप एक दूसरा, टाई ब्रेकर पेश करेंगे सूची द्वारा क्रम।

1

आप इसे कुछ कथन में लपेटने का प्रयास कर सकते हैं, मुझे नहीं लगता कि यह एक ही में संभव है। तो उदाहरण के लिए, मान लें कि आप 10 वीं पंक्ति को अपडेट करने जा रहे हैं। आप 10 के बाद प्रत्येक रिकॉर्ड को बंप अप करना चाहते हैं।

UPDATE table SET col=col+1 WHERE col > 10 
UPDATE table SET col=10 WHERE id = X 
... 

लेकिन सभी आवश्यक तर्कों में रोल करना वाकई मुश्किल है। क्योंकि कुछ अभिलेखों में शायद कमी की आवश्यकता हो, आदि .. आप डुप्लिकेट से बचना चाहते हैं, आदि ..

डेवलपर समय बनाम लाभ के संदर्भ में इस बारे में सोचें।

क्योंकि अगर कोई प्रति दिन एक बार ऐसा करता है, तो ओवरहेड न्यूनतम है, संग्रहीत प्रक्रिया में इसे ठीक करने की तुलना में, या इस सुविधा को छद्म-अनुकूलित करने के लिए, ताकि आप 20 क्वेरी नहीं चला सकें। यदि यह दिन में 100 बार नहीं चलता है, तो 20 प्रश्न पूरी तरह से ठीक हैं।

0

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

एक बेहतर विकल्प प्रत्येक परिवर्तन रिकॉर्ड करने के लिए हो सकता है के रूप में एक इतिहास तो कुछ इस तरह करते हैं:

उदाहरण के लिए, स्थिति 10 नीचे ले जाया जाता है दो 12 वीं

UPDATE table SET display_order = display_order -1 WHERE display_order BETWEEN 10 AND 12 
UPDATE table SET display_order = 12 WHERE row_id = [id of what was row 10] 
10

लिए आपको पहले स्तंभ है कि यह सुनिश्चित करना चाहिए कोई अद्वितीय सूचकांक नहीं है, अन्यथा mysql आपको बताएगा कि क्वेरी के दौरान बाधा टूट गई है। इसके बाद आप चीजें कर सकते हैं जैसे:

-- Move #10 down (i.e. swap #10 and #11) 
UPDATE mytable SET display_order = 
    CASE display_order 
    WHEN 10 THEN 11 
    WHEN 11 THEN 10 
    END CASE 
WHERE display_order BETWEEN 10 AND 11; 

-- Move #4 to #10 
UPDATE mytable SET display_order 
    CASE display_order 
    WHEN 4 THEN 10 
    ELSE display_order - 1 
    END CASE 
WHERE display_order BETWEEN 4 AND 10; 

लेकिन आपको वास्तव में यह सुनिश्चित करना चाहिए कि आप एक ही चरण में चीजें करते हैं। दो चरणों में स्वैपिंग के परिणामस्वरूप यदि आईडी का उपयोग नहीं किया जाता है तो टूटी हुई संख्या होगी। i.e .:

-- Swap in two steps will not work as demostrated here: 

UPDATE mytable SET display_order = 10 WHERE display_order = 11; 
-- Now you have two entries with display_order = 10 

UPDATE mytable SET display_order = 11 WHERE display_order = 10; 
-- Now you have two entries with display_order = 11 (both have been changed) 

और यहां CASE statement of mysql का संदर्भ है।

+0

मैं इस तर्क समस्या को हल करने के लिए PHP का उपयोग करने की कोशिश कर रहा हूं अपने स्वयं के 'UNIQUE' इंडेक्स के खिलाफ अपना सिर मार रहा हूं। मुझे बस उस इंडेक्स को हटा देना चाहिए जैसा आपने कहा था! मैं डेटाबेस में त्रुटियों को पेश करने के बारे में चिंतित था। – Xeoncross

0

एक अस्थायी चर में नई व्यवस्था को एकत्र करें और व्यवस्थापक क्षेत्र के लिए एक "इस आदेश को सहेज" बटन डाल दिया। फिर एक दौर के साथ पंक्तियों के लिए आदेश को बचाओ।

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

आखिरकार, यह एक पूरी पुनर्व्यवस्था के लिए एक कम लागत समाधान हो सकता है और अद्यतन अनुकूलन पर कुछ कोडिंग की बचत होगी।

1

मैं इस समस्या के बारे में सोच रहा हूँ, और समाधान मैं आया आदेश के रूप में एक दशमलव संख्या होने और अगले और पिछले आइटम के बीच एक संख्या के लिए आइटम परिवर्तन की संख्या में परिवर्तन किया गया है

Order Item 
----- ---- 
1  Original Item 1 
2  Original Item 2 
3  Original Item 3 
4  Original Item 4 
5  Original Item 5 

आप 2 स्थिति के लिए आइटम 4 बदलते हैं, तो आपको मिलेगा:

Order Item 
----- ---- 
1  Original Item 1 
1.5  Original Item 4 
2  Original Item 2 
3  Original Item 3 
5  Original Item 5 

आप 3 स्थिति के लिए आइटम 3 बदलते हैं, तो आपको मिलेगा:

Order Item 
----- ---- 
1  Original Item 1 
1.5  Original Item 4 
1.75  Original Item 3 
2  Original Item 2 
5  Original Item 5 

सैद्धांतिक रूप से दो दशमलव के बीच हमेशा एक दशमलव होता है, लेकिन आप कुछ भंडारण सीमा का सामना कर सकते हैं।

इस तरह आप केवल पंक्ति अपडेट करना पड़ता है फिर से आदेश दिया जा रहा।

+0

मुझे लगता है कि इसके साथ दो समस्याएं हैं, फिर भी आपको कुछ फ़ील्ड अपडेट करने की आवश्यकता हो सकती है लेकिन कम से कम नहीं ... यह समय के बाद थोड़ा बालों वाला हो सकता है! मेरे पास एक समान अवधारणा थी लेकिन 100 की इकाइयों में शुरू हुई, इसलिए कम से कम दशमलव की बजाय इनट्स थी लेकिन बहुत अलग नहीं था ... मैं कहूंगा कि आप अभी भी ऑर्डर अपडेट करना चाहते हैं और फिर सामान्य संगत संख्याएं बनना चाहते हैं। योगदान के लिए धन्यवाद। –

+0

यह लगातार सॉर्टिंग के लिए इतना अच्छा काम नहीं कर सकता है ताकि आप शीर्ष पर आइटम जोड़ने या स्थानांतरित कर सकें (उदाहरण के लिए समाचार आइटम) ताकि आप 0.1, 0.0001 के साथ समाप्त हो जाएंगे - लेकिन फिर मुझे लगता है कि यह हजारों में जा सकता है ... हालांकि यह एक थोड़ा बाएं क्षेत्र विचार मैं वास्तव में इस समाधान की दिशा में झुकाव हूँ ... –

+0

मैं मानता हूँ कि यह समय के बाद एक छोटे से बालों प्राप्त कर सकते हैं कि लगता है, लेकिन मुझे नहीं यकीन है कि अगर उपयोगकर्ता को फिर से आदेश देगा कि बहुत (मैं कर रहा हूँ अनुमान है कि यह साइट प्रकार, आदि पर निर्भर करता है) और आप चीजों को और अधिक साफ रखने के लिए हर महीने या "सामान्य" क्वेरी चला सकते हैं। –

1

आप आप पंक्तियों खींचें करने के लिए की जरूरत है, यह एक linked list के लिए एक अच्छा कार्यान्वयन है।

अपनी पंक्तियों के बाद एक linked list साथ आदेश दिया मतलब यह है कि आप एक समय में अधिक से अधिक 3 पंक्तियों अद्यतन करेगा - भले ही आप पूरे ब्लॉक को स्थानांतरित (जब तक यह सन्निहित है के रूप में)।

इस तरह से अपनी पंक्तियों वाली तालिका बनाएँ:

CREATE TABLE t_list (
     id INT NOT NULL PRIMARY KEY, 
     parent INT NOT NULL, 
     value VARCHAR(50) NOT NULL, 
     /* Don't forget to create an index on PARENT */ 
     KEY ix_list_parent ON (parent) 
) 

id parent value 

1 0  Value1 
2 3  Value2 
3 4  Value3 
4 1  Value4 

और क्रम में पंक्तियों का चयन करने के लिए इस MySQL क्वेरी का उपयोग करें:

SELECT @r := (
     SELECT id 
     FROM t_list 
     WHERE parent = @r 
     ) AS id 
FROM (
     SELECT @r := 0 
     ) vars, 
     t_list 

यह आपके लिंक्ड सूची पार और आदेश दिया आइटम वापस आ जाएगी :

id parent value 

1 0  Value1 
4 1  Value4 
3 4  Value3 
2 3  Value2 

पंक्ति को स्थानांतरित करने के लिए, आपकोअपडेट करना होगा पंक्ति के, वर्तमान बच्चे के parent, और उस पंक्ति के parent जो आप पहले डालने वाले हैं।

कैसे MySQL में कुशलता से यह करने के लिए पर अपने ब्लॉग में लेख की इस श्रृंखला देखें:

  • Sorting lists - एक लिंक्ड सूची से आदेश दिया आइटम का चयन करने के लिए कैसे
  • Sorting lists: moving items - कैसे एक आइटम ले जाने के लिए
  • Sorting lists: adding items - कैसे एक आइटम डालने के लिए
  • Sorting lists: deleting items - कैसे एक आइटम को हटाने के लिए
  • Sorting lists: moving blocks - एक सन्निहित ब्लॉक
  • Sorting lists: deleting blocks स्थानांतरित करने के लिए कैसे - क्योंकि वहाँ पंक्ति लॉकिंग के साथ कुछ मुद्दों जो प्रत्येक मामले के लिए कुछ अलग ढंग से संभाला जाना चाहिए रहे हैं कि कैसे एक सन्निहित ब्लॉक

लेख के बहुत सारे हैं नष्ट करने के लिए।

+0

यह बहुत जटिल ... मेरा मुख्य सोचा इसे और अधिक काम करने के बजाय जोड़ने है है एक आइटम यह हर आदेश को बदलने के लिए 3 क्षेत्रों ... बजाय –

+0

3 क्षेत्रों 1 अद्यतन करता है के आदेश को अद्यतन करने लगता है 2009 में एक समस्या नहीं है :) यदि आपके पास 1,000 से अधिक पंक्तियां और लगातार अपडेट होंगे, तो लिंक की गई सूची यह सबसे अच्छा निर्णय है, क्योंकि यह हमेशा 3 फ़ील्ड है, इससे कोई फर्क नहीं पड़ता। अन्य समाधानों को या तो सभी फ़ील्ड या बाइनरी सॉर्ट को अपडेट करने की आवश्यकता होगी जो मूल्यों से बाहर होने की संभावना है। – Quassnoi

11

soulmerge के जवाब ने मुझे सोचा और मुझे लगता है कि यह एक बेहतर समाधान है। आपको क्या करने की आवश्यकता है आईडी() का उपयोग कर आईडी के साथ पंक्तियों का चयन करें और फिर मान सेट करने के लिए CASE का उपयोग करें।

UPDATE mytable SET display_order = 
    CASE id 
    WHEN 10 THEN 1 
    WHEN 23 THEN 2 
    WHEN 4 THEN 3 
    END CASE 
WHERE id IN (10, 23, 4) 

मुझे अपने वर्तमान ऐप में इसकी आवश्यकता है। PHP में, मुझे jQuery UI की अंतर्निहित सॉर्ट करने योग्य सुविधा से आईडी का एक क्रमबद्ध (और आदेश दिया गया) सेट मिल रहा है। तो सरणी इस तरह दिखता है:

$new_order = array(4, 2, 99, 15, 32); // etc 

एकल MySQL अद्यतन क्वेरी बनाने के लिए, मैं यह कर:

$query = "UPDATE mytable SET display_order = (CASE id "; 
foreach($new_order as $sort => $id) { 
    $query .= " WHEN {$id} THEN {$sort}"; 
} 
$query .= " END CASE) WHERE id IN (" . implode(",", $new_order) . ")"; 

अंत में "फटना" बस मुझे में के लिए मेरा पहचान पत्र सूची प्रदान करती है() । यह मेरे लिए खूबसूरती से काम करता है।

+1

यह चालाक है! जब सूची का आदेश दिया जाता है या सूची से तत्व हटा दिया जाता है, तब भी मैं एक अद्यतन को फायर करता हूं, केवल एक क्वेरी। – Kumar

+0

मुझे नहीं लगता कि सिंटैक्स यहां सही है। उदाहरण के लिए, यह केवल "अंत" होना चाहिए और "अंत कारण" नहीं होना चाहिए। – Andrew

+0

MySQL के लिए, आपको 'अंत केस' का उपयोग करने की आवश्यकता है। रेफरी: http: http://dev.mysql.com/doc/refman/5.7/en/case.html –

1

यह डेटाबेस पर आइटम्स को सॉर्ट करने का एक शानदार तरीका है। बिल्कुल वही जो मैं खोज रहा था;)

यहां जामोन होल्मग्रेन के संस्करण का एक बेहतर संस्करण है। यह समारोह पूरी तरह से गतिशील है:

function reOrderRows($tablename, $ordercol, $idsarray){ 

    $query = "UPDATE $tablename SET $ordercol = (CASE $ordercol "; 
    foreach($idsarray as $prev => $new) { 
     $query .= " WHEN $prev THEN $new\n"; 
    } 
    $query .= " END) WHERE $ordercol IN (" . implode(",", array_keys($idsarray)) . ")"; 

    mysql_query($query); 
} 

इसका मतलब यह है कि आप अपनी मेज पर एक स्तंभ $ ordercol है $ tablename सिर्फ आदेश देने के प्रयोजनों के लिए।

$ idsarray ("current_order_num" => "updated_order_num") प्रारूप सरणी में एक सरणी है।

तो यदि आप बस अपनी तालिका में दो लाइनों को स्वैप करना चाहते हैं (कल्पना करें कि आपके उदाहरण के लिए आपके वेबपृष्ठ पर "ऊपर जाना" और "नीचे जाना" आइकन हैं), तो आप इस फ़ंक्शन का उपयोग पिछले एक के शीर्ष पर कर सकते हैं :

function swapRows($tablename, $ordercol, $firstid, $secondid){ 
    $swaparray = array("$firstid" => "$secondid", "$secondid" => "$firstid"); 
    reOrderRows($tablename, $ordercol, $swaparray); 
} 
4

एक छोटी सी देर है, लेकिन यह किसी और के लिए उपयोगी हो सकता है:

UPDATE mytable SET display_order = FIND_IN_SET(rowId, '1,9,2,6,23') WHERE rowId in (1,9,2,6,23)