شرح - type data in sql server




SQL Server: كيفية الانضمام إلى الصف الأول (7)

@ الإجابة Quassnoi جيدة ، في بعض الحالات (خاصة إذا كان الجدول الخارجي كبير) ، قد يكون الاستعلام الأكثر كفاءة باستخدام وظائف windowed ، مثل:

SELECT  Orders.OrderNumber, LineItems2.Quantity, LineItems2.Description
FROM    Orders
LEFT JOIN 
        (
        SELECT  LineItems.Quantity, LineItems.Description, OrderId, ROW_NUMBER()
                OVER (PARTITION BY OrderId ORDER BY (SELECT NULL)) AS RowNum
        FROM    LineItems

        ) LineItems2 ON LineItems2.OrderId = Orders.OrderID And RowNum = 1

في بعض الأحيان تحتاج فقط إلى اختبار أي استعلام يعطي أداء أفضل.

سأستخدم مثالًا ملموسًا لكن افتراضيًا.

يحتوي كل طلب عادة على بند واحد فقط:

أوامر:

OrderGUID   OrderNumber
=========   ============
{FFB2...}   STL-7442-1      
{3EC6...}   MPT-9931-8A

LineItems:

LineItemGUID   Order ID Quantity   Description
============   ======== ========   =================================
{098FBE3...}   1        7          prefabulated amulite
{1609B09...}   2        32         spurving bearing

ولكن في بعض الأحيان ، سيكون هناك طلب يتضمن عنصرين:

LineItemID   Order ID    Quantity   Description
==========   ========    ========   =================================
{A58A1...}   6,784,329   5          pentametric fan
{0E9BC...}   6,784,329   5          differential girdlespring 

عادةً عند عرض الطلبات على المستخدم:

SELECT Orders.OrderNumber, LineItems.Quantity, LineItems.Description
FROM Orders
    INNER JOIN LineItems 
    ON Orders.OrderID = LineItems.OrderID

أرغب في إظهار العنصر الواحد في الطلب. ولكن مع هذا الترتيب العرضي الذي يحتوي على عنصرين (أو أكثر) ، تظهر الطلبات مكررة :

OrderNumber   Quantity   Description
===========   ========   ====================
STL-7442-1    7          prefabulated amulite
MPT-9931-8A   32         spurving bearing
KSG-0619-81   5          panametric fan
KSG-0619-81   5          differential girdlespring

ما أريده حقًا هو أن يكون خادم SQL مجرد اختيار واحد ، لأنه سيكون جيدًا بما فيه الكفاية :

OrderNumber   Quantity   Description
===========   ========   ====================
STL-7442-1    7          prefabulated amulite
MPT-9931-8A   32         differential girdlespring
KSG-0619-81   5          panametric fan

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

OrderNumber   Quantity   Description
===========   ========   ====================
STL-7442-1    7          prefabulated amulite
MPT-9931-8A   32         differential girdlespring
KSG-0619-81   5          panametric fan, ...

لذا فإن السؤال هو كيف

  • إزالة صفوف "مكررة"
  • انضم فقط إلى أحد الصفوف ، لتجنب الازدواجية

المحاولة الأولى

كانت أول محاولة ساذجة تتمثل في الانضمام فقط إلى عناصر السطر " TOP 1 ":

SELECT Orders.OrderNumber, LineItems.Quantity, LineItems.Description
FROM Orders
    INNER JOIN (
       SELECT TOP 1 LineItems.Quantity, LineItems.Description
       FROM LineItems
       WHERE LineItems.OrderID = Orders.OrderID) LineItems2
    ON 1=1

لكن هذا يعطي الخطأ:

لا يتطابق العمود أو البادئة "الطلبات" مع اسم الجدول أو الاسم المستعار المستخدم في الاستعلام.

يفترض أن التحديد الداخلي لا يرى الجدول الخارجي.


، aproach آخر باستخدام تعبير الجدول المشترك:

with firstOnly as (
    select Orders.OrderNumber, LineItems.Quantity, LineItems.Description, ROW_NUMBER() over (partiton by Orders.OrderID order by Orders.OrderID) lp
    FROM Orders
        join LineItems on Orders.OrderID = LineItems.OrderID
) select *
  from firstOnly
  where lp = 1

أو ، في النهاية ربما تريد إظهار كل الصفوف التي تم ضمها؟

نسخة مفصولة بفاصلة هنا:

  select *
  from Orders o
    cross apply (
        select CAST((select l.Description + ','
        from LineItems l
        where l.OrderID = s.OrderID
        for xml path('')) as nvarchar(max)) l
    ) lines

أقوم بحل مشكلة مشابهة باستخدام LEFT JOIN و GROUP BY Orders.OrderNumber. هل هناك سبب لعدم القيام بذلك بهذه الطريقة؟

SELECT Orders.OrderNumber, LineItems.Quantity, LineItems.Description
FROM Orders
    LEFT JOIN LineItems 
    ON Orders.OrderID = LineItems.OrderID
GROUP BY Orders.OrderNumber

سأجيب على إجابتك عن إجابتك بإجابة في سؤالك الخاص:

Orders             LineItems
+-------------+    +---------+----------+---------------+
| OrderNumber |    | OrderID | Quantity | Description   |
+-------------+    +---------+----------+---------------+
| 22586       |    | 22586   | 17       | Trunion       |
+-------------+    | 22586   | 3        | Girdle Spring |
                   +---------+----------+---------------+

الانضمام إلى الاثنين معا على OrderNumber يعطي:

OrderNumber  Quantity  Description
-----------  --------  -------------
22586        17        Trunion
22586        3         Girdle Spring

2 row(s) affected

حيث أردنا أن نرجع صفًا واحدًا فقط:

OrderNumber  Quantity  Description
-----------  --------  -------------
22586        17        Trunion

1 row(s) affected

هذا هو السبب في أنني أستخدم GROUP BY Orders.OrderNumber والذي لا يعرض سوى صف واحد لكل OrderNumber.


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

select * from users join widgets on widgets.id = (
    select id from widgets
    where widgets.user_id = users.id
    order by created_at desc
    limit 1
)

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

إليك طلب البحث المعدل:

SELECT Orders.OrderNumber, max(LineItems.Quantity), max(LineItems.Description)
FROM Orders
    INNER JOIN LineItems 
    ON Orders.OrderID = LineItems.OrderID
Group by Orders.OrderNumber

طريقي المفضلة لتشغيل هذا الاستعلام هو جملة غير موجودة. أعتقد أن هذه هي الطريقة الأكثر فعالية لتشغيل هذا النوع من الاستعلامات:

select o.OrderNumber,
       li.Quantity,
       li.Description
from Orders as o
inner join LineItems as li
on li.OrderID = o.OrderID
where not exists (
    select 1
    from LineItems as li_later
    where li_later.OrderID = o.OrderID
    and li_later.LineItemGUID > li.LineItemGUID
    )

لكني لم اختبر هذه الطريقة ضد الطرق الأخرى المقترحة هنا.


SELECT   Orders.OrderNumber, LineItems.Quantity, LineItems.Description
FROM     Orders
JOIN     LineItems
ON       LineItems.LineItemGUID =
         (
         SELECT  TOP 1 LineItemGUID 
         FROM    LineItems
         WHERE   OrderID = Orders.OrderID
         )

في SQL Server 2005 والإصدارات الأحدث ، يمكنك فقط استبدال INNER JOIN مع CROSS APPLY :

SELECT  Orders.OrderNumber, LineItems2.Quantity, LineItems2.Description
FROM    Orders
CROSS APPLY
        (
        SELECT  TOP 1 LineItems.Quantity, LineItems.Description
        FROM    LineItems
        WHERE   LineItems.OrderID = Orders.OrderID
        ) LineItems2




sql-server-2000