it-swarm.asia

لماذا يتم فرز القيم الخالية أولاً؟

لماذا عندما يكون لدينا قيمة فارغة في عمود ونرتب حسب القيمة تصاعديًا ، يتم فرز القيم الفارغة أولاً؟

select 1 as test
union all
select 2
union all
select NULL
union all
select 3
union all
select 4
order by test

النتائج في

NULL
1
2
3
4

ما زلت أفكر في NULL تعني "غير محدد" أو "غير معروف" ممكن. إذا كان هذا صحيحًا ، ألن يتم ترتيبه نهائيًا ، حيث يمكن أن تكون القيمة أكبر من جميع القيم الأخرى؟ (أو هل هذا خيار فرز في مكان ما؟)

أنا على SQL Server 2008R2 ، لكني أشك في أن هذا صحيح عبر جميع خوادم SQL ، وربما عبر جميع RDBMSs.

20
Richard

BOL : تشير قيمة NULL إلى أن القيمة غير معروفة. تختلف قيمة NULL عن قيمة فارغة أو قيمة صفرية. ليست هناك قيمتان فارغتان متساويتان. المقارنات بين قيمتين فارغتين ، أو بين NULL وأي قيمة أخرى ، ترجع غير معروفة لأن قيمة كل NULL غير معروفة.

NULL تعني غير معروف. لا يوجد تفسير آخر صالح.

إذا كان هذا صحيحًا ، ألن يتم ترتيبه نهائيًا ، نظرًا لأن القيمة يمكن أن تكون أكبر من جميع القيم الأخرى؟

لا يوجد يمكن أن يكون . لا توجد قيمة محتملة قيمة. غير معروف غير معروف غير معروف.

بالنسبة إلى سبب ظهوره أولاً ، بدلاً من الأخير ، لا يتم تلبية ذلك من خلال معايير SQL المنشورة ، وللأسف يُترك لتقدير مورد RDBMS:

Wikipedia : لا يحدد معيار SQL بشكل صريح ترتيب فرز افتراضي للقيم الخالية. بدلاً من ذلك ، في الأنظمة المطابقة ، يمكن فرز القيم الفارغة قبل أو بعد جميع قيم البيانات باستخدام عبارات NULLS FIRST أو NULLS LAST من قائمة ORDER BY ، على التوالي. ومع ذلك ، لا يقوم جميع موردي DBMS بتنفيذ هذه الوظيفة. قد يحدد البائعون الذين لا يقومون بتنفيذ هذه الوظيفة معالجات مختلفة للفرز Null في DBMS.

20
Mark Storey-Smith

أنت محق في أن NULL يمكن أن تعني "غير محدد" أو "Uknownn" أو "غير معروف بعد" أو "لم يتم التقديم". ولكن لا يوجد سبب لوضع Nulls أولاً أو أخيرًا. إذا لم نكن نعرف القيم الحقيقية ، فيمكن أن تكون صغيرة أو كبيرة.

أعتقد أن معيار تحديد السلوك المطلوب للقيم الخالية أثناء الفرز هو:

ORDER BY 
    test NULLS LAST                      --- or NULLS FIRST for the opposite

لسوء الحظ لم يعتمد SQL-Server بناء الجملة هذا حتى الآن. إذا لم أكن مخطئا PostgreSQL وأوراكل ذلك.

حل واحد:

ORDER BY 
     CASE WHEN test IS NOT NULL 
            THEN 0 
          ELSE 1 
     END 
   , test

حل آخر يحتاج إلى تعديل اعتمادًا على نوع البيانات - ولكنه لن يعمل بشكل جيد ، لأنه لا يمكنه استخدام فهرس على (test):

ORDER BY 
    COALESCE(test, 2147483647)               --- if it's a 4-byte signed integer
6
ypercubeᵀᴹ

لا أعلم لماذا يتم ذلك بهذه الطريقة ، ولكن بحكم التعريف لا يمكن مقارنة القيم الخالية بالقيم الخالية ، لذا يجب عليهم الذهاب في البداية أو النهاية (إجابة مارك تغطي هذا في المزيد من التفاصيل).

للحصول على السلوك الذي تريده - على حد علمي ، لا يوجد خيار فرز لوضع القيم الفارغة في النهاية ، لذلك يجب عليك إزعاجه باستخدام عمود محسوب لفرضها آخرًا. ومع ذلك ، في SQL Server ، لا يمكنك الطلب حسب عمود محسوب (CASE WHEN ...) عندما تحتوي بياناتك على عامل تعيين (UNION ALL). وبالتالي:

CREATE TABLE #sorttest(test int)
INSERT INTO #sorttest values(1)
INSERT INTO #sorttest values(5)
INSERT INTO #sorttest values(4)
INSERT INTO #sorttest values(NULL)
INSERT INTO #sorttest values(3)
INSERT INTO #sorttest values(2)
SELECT test
FROM #sorttest
ORDER BY CASE WHEN test IS NULL THEN 1 ELSE 0 END, test

DROP TABLE #sorttest

ستعمل لفرز القيم الخالية أخيرا. إذا كان عليك استخدام UNION (أو EXCEPT أو INTERSECTS) لإنشاء مجموعة بياناتك ، فقم بتفريغ بياناتك إلى جدول مؤقت كما هو موضح أعلاه.

3
Simon Righarts

إذا كنت تتعامل مع أرقام يمكنك استخدامها

ORDER BY -test DESC

NULL هي أدنى القيم الممكنة ، لذلك يضعها DESC في النهاية. في هذه الأثناء ، لا تحتوي القيم غير الفارغة على العلامة بحيث يكون DESC في الواقع ASC على القيم الحقيقية. يجب أن يكون هذا أسرع من CASE وأفترض أن محسّن الاستعلام يمكنه أيضًا استخدام الفهارس في العمود test.

0
Luca