मनमाने ढंग से एक तालिका में रिकॉर्ड आदेश


28

एक डेटाबेस का उपयोग करते समय एक सामान्य आवश्यकता क्रम में रिकॉर्ड का उपयोग करना है। उदाहरण के लिए, यदि मेरे पास एक ब्लॉग है, तो मैं अपने ब्लॉग पोस्ट को अनियंत्रित क्रम में पुन: व्यवस्थित करने में सक्षम होना चाहता हूं। इन प्रविष्टियों में अक्सर बहुत सारे संबंध होते हैं, इसलिए एक संबंधपरक डेटाबेस समझ में आता है।

सामान्य समाधान जो मैंने देखा है वह पूर्णांक कॉलम जोड़ना है order:

CREATE TABLE AS your_table (id, title, sort_order)
AS VALUES
  (0, 'Lorem ipsum',   3),
  (1, 'Dolor sit',     2),
  (2, 'Amet, consect', 0),
  (3, 'Elit fusce',    1);

फिर, हम orderउन्हें उचित क्रम में प्राप्त करने के लिए पंक्तियों को क्रमबद्ध कर सकते हैं ।

हालाँकि, यह अनाड़ी लगता है:

  • यदि मैं रिकॉर्ड 0 को प्रारंभ में ले जाना चाहता हूं, तो मुझे हर रिकॉर्ड को पुनः व्यवस्थित करना होगा
  • अगर मैं बीच में नया रिकॉर्ड डालना चाहता हूं, तो मुझे इसके बाद हर रिकॉर्ड को फिर से दर्ज करना होगा
  • यदि मुझे कोई रिकॉर्ड निकालना है, तो मुझे उसके बाद हर रिकॉर्ड को फिर से लिखना होगा

ऐसी स्थितियों की कल्पना करना आसान है:

  • दो रिकॉर्ड समान हैं order
  • orderबीच के रिकॉर्ड में अंतराल हैं

ये कई कारणों से आसानी से हो सकते हैं।

यह दृष्टिकोण है कि जूमला जैसे अनुप्रयोग हैं:

आदेश देने के लिए जूमला के दृष्टिकोण का उदाहरण

आप तर्क दे सकते हैं कि यहाँ इंटरफ़ेस खराब है, और यह कि मनुष्यों के बजाय सीधे संख्याओं को संपादित करने के लिए, उन्हें तीर या ड्रैग-एंड-ड्रॉप का उपयोग करना चाहिए और आप शायद सही होंगे। लेकिन पर्दे के पीछे भी वही हो रहा है।

कुछ लोगों ने ऑर्डर को स्टोर करने के लिए एक दशमलव का उपयोग करने का प्रस्ताव दिया है, ताकि आप "2.5" का उपयोग ऑर्डर 2 और 3 के रिकॉर्ड के बीच में रिकॉर्ड कर सकें। और जब यह थोड़ी मदद करता है, तो यकीनन यह और भी ज्यादा गड़बड़ है क्योंकि आप इसे समाप्त कर सकते हैं अजीब दशमलव (आप कहाँ रुकते हैं? 2.75? 2.875? 2.8125?)

क्या ऑर्डर को टेबल में स्टोर करने का एक बेहतर तरीका है?


5
बस तुम इतना जानते हो । । । "इस तरह के सिस्टम को" रिलेशनल "कहा जाता है, यह है कि शब्द का संबंध मूल रूप से एक तालिका के लिए सिर्फ एक गणितीय शब्द है ।" - डेटाबेस सिस्टम , CJ दिनांक, 7 वें संस्करण का एक परिचय । पृष्ठ 25
माइक शेरिल 'कैट रिकॉल'


@ MikeSherrill'CatRecall 'है कि मैं पकड़ नहीं था, मैं पुराने ordersऔर ddl के साथ सवाल तय कर दिया है ।
इवान कैरोल

जवाबों:


17

यदि मैं रिकॉर्ड 0 को प्रारंभ में ले जाना चाहता हूं, तो मुझे हर रिकॉर्ड को पुनः व्यवस्थित करना होगा

नहीं, एक सरल तरीका है।

update your_table
set order = -1 
where id = 0;

अगर मैं बीच में नया रिकॉर्ड डालना चाहता हूं, तो मुझे इसके बाद हर रिकॉर्ड को फिर से दर्ज करना होगा

यह सच है, जब तक कि आप एक डेटा प्रकार का उपयोग नहीं करते हैं जो "मान" के बीच का समर्थन करता है। फ्लोट और न्यूमेरिक प्रकार आपको मान को अद्यतन करने की अनुमति देते हैं, कहते हैं, 2.5। लेकिन varchar (n) काम करता है, भी। (सोचो 'a', 'b', 'c'; फिर सोचो 'ba', 'bb', 'bc'।)।

यदि मुझे कोई रिकॉर्ड निकालना है, तो मुझे उसके बाद हर रिकॉर्ड को फिर से लिखना होगा

नहीं, एक सरल तरीका है। बस पंक्ति को हटा दें। शेष पंक्तियाँ अभी भी सही ढंग से क्रमबद्ध होंगी।

ऐसी स्थितियों की कल्पना करना आसान है:

दो अभिलेखों का क्रम समान है

एक अनोखी बाधा को रोका जा सकता है।

अभिलेखों के बीच क्रम में अंतराल हैं

एक dbms एक कॉलम में मानों को कैसे सॉर्ट करता है, इस पर अंतराल का कोई प्रभाव नहीं होता है।

कुछ लोगों ने ऑर्डर को स्टोर करने के लिए एक दशमलव का उपयोग करने का प्रस्ताव दिया है, ताकि आप "2.5" का उपयोग ऑर्डर 2 और 3 के रिकॉर्ड के बीच में रिकॉर्ड कर सकें। और जब यह थोड़ी मदद करता है, तो यकीनन यह और भी ज्यादा गड़बड़ है क्योंकि आप इसे समाप्त कर सकते हैं अजीब दशमलव (आप कहाँ रुकते हैं? 2.75? 2.875? 2.8125?)

आपको तब तक नहीं रोकना है जब तक आपको नहीं करना है। Dbms में दशमलव बिंदु के बाद 2, 7, या 15 स्थानों वाले मानों को छाँटने की कोई समस्या नहीं है।

मुझे लगता है कि आपकी वास्तविक समस्या यह है कि आप पूर्णांक के रूप में क्रमबद्ध मानों को देखना चाहेंगे । तुम यह कर सकते हो।

create table your_table (
  id int primary key, 
  title varchar(13), 
  sort_order float
);

insert into your_table values
(0, 'Lorem ipsum', 2.0),
(1, 'Dolor sit', 1.5),
(2, 'Amet, consect', 0.0),
(3, 'Elit fusce', 1.0);

-- This windowing function will "transform" the floats into sorted integers.
select id, title,
       row_number() over (order by sort_order)
from your_table

with cte as (select *,row_number() over (order by sort_order desc) as row from test) update cte set sort_order=row;
नीरसता

यहां एक अतिरिक्त संकेत दिया गया है: यदि आप चाहते हैं कि यह वास्तव में परिपूर्ण हो, तो आपको जांचना चाहिए कि क्या आप अधिक पंक्तियों को आगे बढ़ा रहे हैं तो आप अछूते रहना चाहते हैं। यदि ऐसा है, तो कई कमियों को अपडेट करें - "अछूता" - वाले; डी
रूबेन बोएक

7

यह बहुत ही सरल है। आपको "कार्डिनैलिटी होल" संरचना की आवश्यकता है:

आपको 2 कॉलम रखने होंगे:

  1. पीके = 32 बिट integer
  2. आदेश = 64 बिट bigint( नहीं double )

सम्मिलित करें / अद्यतन

  1. पहला नया रिकॉर्ड सम्मिलित करते समय, सेट करें order = round(max_bigint / 2)
  2. तालिका की शुरुआत में सम्मिलित करते समय, सेट करें order = round("order of first record" / 2)
  3. तालिका के अंत में सम्मिलित करते समय, order = round("max_bigint - order of last record" / 2) 4 सेट करें ) मध्य में सम्मिलित करते समय, सेट करेंorder = round("order of record before - order of record after" / 2)

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

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

फ़्लोटिंग पॉइंट प्रकारों का उपयोग न करना याद रखें - ऑर्डर का सटीक मान होना चाहिए!


4

आम तौर पर, रिकॉर्ड, शीर्षक, आईडी, या उस विशेष स्थिति के लिए जो भी उपयुक्त हो, में कुछ जानकारी के अनुसार ऑर्डर किया जाता है।

यदि आपको एक विशेष ऑर्डरिंग की आवश्यकता है, तो पूर्णांक कॉलम का उपयोग करना उतना बुरा नहीं है जितना यह लग सकता है। उदाहरण के लिए, 5 वें स्थान पर जाने के रिकॉर्ड के लिए जगह बनाने के लिए, आप कुछ ऐसा कर सकते हैं:

update table_1 set place = place + 1 where place > 5

उम्मीद है कि आप कॉलम को घोषित कर सकते हैं uniqueऔर शायद पुनर्व्यवस्थित करने के लिए एक प्रक्रिया है "परमाणु"। विवरण प्रणाली पर निर्भर करता है लेकिन यह सामान्य विचार है।


4

... यह यकीनन भी गड़बड़ है क्योंकि आप अजीब दशमलव के साथ समाप्त हो सकते हैं (आप कहाँ रुकते हैं? 2.75? 2.8? 125 /?)

किसे पड़ी है? ये संख्याएं केवल कंप्यूटर से निपटने के लिए हैं, इसलिए इससे कोई फर्क नहीं पड़ता कि उनके पास कितने भिन्नात्मक अंक हैं या वे हमारे लिए कितने बदसूरत हैं।

दशमलव मानों का उपयोग करने का मतलब है कि आइटम J और K के बीच आइटम F को स्थानांतरित करने के लिए आपको केवल J और K के लिए ऑर्डर मानों का चयन करना होगा और फिर उन्हें औसत करना होगा। फिर F. दो चयनित स्टेटमेंट और एक अपडेट स्टेटमेंट को अपडेट करें (संभवत: बचने के लिए क्रमिक अलगाव का उपयोग करके। गतिरोध)।

यदि आप आउटपुट में भिन्न के बजाय पूर्णांक देखना चाहते हैं, तो क्लाइंट अनुप्रयोग में पूर्णांकों की गणना करें या ROW_NUMBER () या RANK () फ़ंक्शन (यदि आपका RDBMS उन्हें शामिल करता है) का उपयोग करें।


1

अपने स्वयं के प्रोजेक्ट में, मैं दशमलव संख्या समाधान के समान एक समाधान की कोशिश कर रहा हूं, लेकिन इसके बजाय बाइट-सरणियों का उपयोग कर रहा हूं:

def pad(x, x_len, length):
    if x_len >= length:
        return x
    else:
        for _ in range(length - x_len):
            x += b"\x00"
        return x

def order_index(_from, _to, count, length=None):
    assert _from != _to
    assert _from < _to

    if not length:
        from_len = len(_from)
        to_len = len(_to)
        length = max(from_len, to_len)

        _from = pad(_from, from_len, length)
        _to = pad(_to, to_len, length)

    from_int = int.from_bytes(_from, "big")
    to_int = int.from_bytes(_to, "big")
    inc = (to_int - from_int)//(count + 1)
    if not inc:
        length += 1
        _from += b"\x00"
        _to += b"\x00"
        return order_index(_from, _to, count, length)

    return (int.to_bytes(from_int + ((x+1)*inc), length, "big") for x in range(count))
>>> index = order_index(b"A", b"Z", 24)
>>> [x for x in index]
[b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y']
>>> 
>>> index = order_index(b"A", b"Z", 25)
>>> [x for x in index]
[b'A\xf6', b'B\xec', b'C\xe2', b'D\xd8', b'E\xce', b'F\xc4', b'G\xba', b'H\xb0', b'I\xa6', b'J\x9c', b'K\x92', b'L\x88', b'M~', b'Nt', b'Oj', b'P`', b'QV', b'RL', b'SB', b'T8', b'U.', b'V$', b'W\x1a', b'X\x10', b'Y\x06']

विचार यह है कि आप कभी भी संभव इन-इन-वेल्यू मूल्यों से बाहर नहीं भाग सकते क्योंकि आप और b"\x00"अधिक मूल्यों की आवश्यकता होने पर शामिल रिकॉर्ड्स में संलग्न करते हैं। ( intपायथन 3 में अनबाउंड है, अन्यथा आपको तुलना करने के लिए बाइट्स का एक टुकड़ा चुनना होगा, यह अनुमान लगाया जा रहा है कि, दो आसन्न मूल्यों के बीच, अंतर समाप्ति की ओर पैक किया जाएगा।)

जैसे, मान लें कि आपके पास दो रिकॉर्ड हैं, b"\x00"और b"\x01", और आप उनके बीच जाना चाहते हैं। वहाँ के बीच किसी भी उपलब्ध मान नहीं हैं 0x00और 0x01इसलिए आप संलग्न, b"\x00"दोनों के लिए, और अब आप उन दोनों के बीच मूल्यों आप नए मूल्यों को सम्मिलित करने के लिए उपयोग कर सकते का एक समूह है।

>>> records = [b"\x00", b"\x01", b"\x02"]
>>> values = [x for x in order_index(records[0], records[1], 3)]
>>> records = records + values
>>> records.sort()
>>> records
[b'\x00', b'\x00@', b'\x00\x80', b'\x00\xc0', b'\x01', b'\x02']

डेटाबेस आसानी से इसे सॉर्ट कर सकता है क्योंकि सब कुछ लेक्सिकोग्राफिक क्रम में समाप्त होता है। यदि आप कोई रिकॉर्ड हटाते हैं, तो यह अभी भी क्रम में है। अपने प्रोजेक्ट में, मैं कर दिया है b"\x00"और b"\xff"के रूप में FIRSTऔर LASTरिकॉर्ड, हालांकि, आदेश "से" आभासी रूप में उन का उपयोग करने के और मूल्यों "से" के लिए आगे जोड़ते / संलग्न नए रिकॉर्ड:

>>> records = []
>>> value = next(order_index(FIRST, LAST, 1))
>>> value
b'\x7f'
>>> records.append(value)
>>> value = next(order_index(records[0], LAST, 1))
>>> value
b'\xbf'
>>> records.append(value)
>>> records.sort()
>>> records
[b'\x7f', b'\xbf']
>>> value = next(order_index(FIRST, records[0], 1))
>>> value
b'?'
>>> records.append(value)
>>> records.sort()
>>> records
[b'?', b'\x7f', b'\xbf']

0

मुझे यह उत्तर बहुत बेहतर लगा। इसे पूरी तरह से उद्धृत करना:

डेटाबेस कुछ चीजों के लिए अनुकूलित हैं। बहुत सारी पंक्तियों को जल्दी से अपडेट करना उनमें से एक है। यह विशेष रूप से सच हो जाता है जब आप डेटाबेस को अपना काम करने देते हैं।

विचार करें:

order song
1     Happy Birthday
2     Beat It
3     Never Gonna Give You Up
4     Safety Dance
5     Imperial March

और आप Beat Itअंत तक जाना चाहते हैं, आपके पास दो प्रश्न होंगे:

update table 
  set order = order - 1
  where order >= 2 and order <= 5;

update table
  set order = 5
  where song = 'Beat It'

और बस। यह बहुत बड़ी संख्या के साथ बहुत अच्छी तरह से बढ़ता है। अपने डेटाबेस में एक काल्पनिक प्लेलिस्ट में कुछ हज़ार गाने डालने की कोशिश करें और देखें कि एक गीत को एक स्थान से दूसरे स्थान पर ले जाने में कितना समय लगता है। चूंकि ये बहुत मानकीकृत रूप हैं:

update table 
  set order = order - 1
  where order >= ? and order <= ?;

update table
  set order = ?
  where song = ?

आपके पास दो तैयार किए गए कथन हैं जो आप बहुत कुशलता से पुन: उपयोग कर सकते हैं।

यह कुछ महत्वपूर्ण लाभ प्रदान करता है - तालिका का क्रम कुछ ऐसा है जिसके बारे में आप तर्क कर सकते हैं। तीसरे गाने में order3 का, हमेशा है। इसकी गारंटी देने का एकमात्र तरीका क्रम के रूप में लगातार पूर्णांक का उपयोग करना है। छद्म से जुड़ी सूचियों या अंतराल के साथ दशमलव संख्या या पूर्णांक का उपयोग करना आपको इस संपत्ति की गारंटी नहीं देगा; इन मामलों में nth गीत प्राप्त करने का एकमात्र तरीका पूरी तालिका को सॉर्ट करना और nth रिकॉर्ड प्राप्त करना है।

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.