كيفية فرز وعرض قوائم مختلطة من Alphas والأرقام كما يتوقع المستخدمون؟

StackOverflow https://stackoverflow.com/questions/552053

سؤال

طلبنا لديه CustomerNumber حقل. لدينا المئات من الأشخاص المختلفين الذين يستخدمون النظام (لكل منها تسجيل الدخول الخاص بهم وقائمة خاصة بهم CustomerNumberس). قد يكون لدى المستخدم الفردي أكثر من 100،000 عميل. كثيرون لديهم أقل من 100.

بعض الناس وضعون الأرقام الفعلية فقط في حقول رقم العملاء، بينما يستخدم الآخرون مزيجا من الأشياء. يتيح النظام 20 حرفا يمكن أن يكون AZ أو 0-9 أو اندفاعة وتخزين هذه في varchar2 (20). يتم إجراء أي شيء أحرف صغيرة قبل تخزينه.

الآن، دعنا نقول أن لدينا تقرير بسيط يسرد جميع العملاء لمستخدم معين، مرتبة حسب رقم العميل. على سبيل المثال

SELECT CustomerNumber,CustomerName
FROM Customer
WHERE User = ?
ORDER BY CustomerNumber;

هذا حلا ساذج لأن الأشخاص الذين يستخدمون الأرقام فقط لا يريدون رؤية فرز أبجدي عادي (حيث يأتي "10" قبل "9").

لا أرغب في طرح أي أسئلة غير ضرورية حول بياناتها.

أستخدم Oracle، لكنني أعتقد أنه سيكون من المثير للاهتمام رؤية بعض الحلول لقواعد البيانات الأخرى. يرجى تضمين قاعدة البيانات التي تعمل إجابتك.

ما رأيك في أفضل طريقة لتنفيذ هذا؟

هل كانت مفيدة؟

المحلول

في أوراكل 10G:

SELECT  cust_name
FROM    t_customer c 
ORDER BY
    REGEXP_REPLACE(cust_name, '[0-9]', ''), TO_NUMBER(REGEXP_SUBSTR(cust_name, '[0-9]+'))

هذا سيفرض من خلال الحدوث الأول للعدد، وليس فيما يتعلق بموقعه، أي:

  1. customer1 < customer2 < customer10
    • cust1omer ? customer1
    • cust8omer1 ? cust8omer2

, ، اين ا ? يعني أن النظام غير محدد.

هذا يكفي لمعظم الحالات.

لإجبار ترتيب الفرز في حالة 2, ، يمكنك إضافة REGEXP_INSTR(cust_name, '[0-9]', n) ل ORDER BY قائمة n مرات، إجبار النظام على ظهور أول n-ذ (2nd, 3rd إلخ.) مجموعة من الأرقام.

لإجبار ترتيب الفرز في حالة 3, ، يمكنك إضافة TO_NUMBER(REGEXP_SUBSTR(cust_name, '[0-9]+', n)) ل ORDER BY قائمة n مرات، إجبار ترتيب n-ذ. مجموعة من الأرقام.

في الممارسة العملية، استعلام كتبت كافية.

يمكنك إنشاء فهرس يستند إلى الدعامات على هذه التعبيرات، ولكن ستحتاج إلى إجباره على تلميح، ومرحلة واحدة SORT ORDER BY سيتم تنفيذها على أي حال، كما CBO لا تثق مؤشرات قاعدة الوظيفة بما يكفي للسماح ORDER BY عليهم.

نصائح أخرى

ربما يكون أفضل رهان لديك هو حساب عمود منفصل مسبقا واستخدام ذلك لطلب رقم العميل واستخدامه لعرضه. من المحتمل أن ينطوي ذلك على الحشو 0 أي أعداد صحيحة داخلية إلى طول ثابت.

الاحتمال الآخر هو القيام بفرز ما بعد الاختيار على النتائج التي تم إرجاعها.

لقد وضع جيف أونوود بلوق نشر حول كيفية حساب بعض الأشخاص أوامر الفرز الصديقة الإنسانية.

هل يمكن أن يكون لديك عمود رقمي [customerernumberint] التي يتم استخدامها فقط عندما يكون عامل التخصيص الرقمي (NULL خلاف ذلك)، ثم

ORDER BY CustomerNumberInt, CustomerNumber

1] اعتمادا على كيفية معالجة إصدار SQL الخاص بك Nulls بالترتيب الخاص بك قد ترغب في التقصير في التقصير إلى الصفر (أو اللانهاية!)

لدي موقف مروع مماثل وتطوير وظيفة فظيعة بشكل مناسب للتعامل معها (SQLServer)

في وضعي، لدي جدول من "الوحدات" (هذا نظام تتبع العمل للطلاب، لذلك تمثل وحدة في هذا السياق دورة يقوم بها). تحتوي الوحدات لديها رمز، والذي بالنسبة للجزء الأكبر من الأكواه، ولكن لأسباب مختلفة تم تصنيعه varchar وقررت بادئة بعضها حتى 5 أحرف. لذلك يتوقعون 53،123،237،356 للفرز بشكل طبيعي، ولكن أيضا T53، T123، T237، T356

Unitcode هو nvarchar (30)

إليك هيئة الوظيفة:

declare @sortkey nvarchar(30)

select @sortkey = 
    case
        when @unitcode like '[^0-9][0-9]%' then left(@unitcode,1) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-1)
        when @unitcode like '[^0-9][^0-9][0-9]%' then left(@unitcode,2) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-2)
        when @unitcode like '[^0-9][^0-9][^0-9][0-9]%' then left(@unitcode,3) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-3)
        when @unitcode like '[^0-9][^0-9][^0-9][^0-9][0-9]%' then left(@unitcode,4) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-4)
        when @unitcode like '[^0-9][^0-9][^0-9][^0-9][^0-9][0-9]%' then left(@unitcode,5) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-5)
        when @unitcode like '%[^0-9]%' then @unitcode
        else left('000000000000000000000000000000',30-len(@unitcode)) + @unitcode
    end 

return @sortkey

أردت أن أطلق النار على نفسي في الوجه بعد كتابة ذلك، ومع ذلك فإنه يعمل ويبدو أنه لا يقتل الخادم عند تشغيله.

لقد استخدمت هذا في SQL Server وتعمل بشكل رائع: هنا الحل هو وسادة القيم الرقمية بحرف موجود في المقدمة بحيث تكون كلها من نفس طول السلسلة.

فيما يلي مثال باستخدام هذا النهج:

select MyCol
from MyTable
order by 
    case IsNumeric(MyCol) 
        when 1 then Replicate('0', 100 - Len(MyCol)) + MyCol
        else MyCol
    end

يجب استبدال 100 بالطول الفعلي لهذا العمود.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top