سؤال

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

لذلك أنا أفكر:

UPDATE sales
SET status = 'ACTIVE'
WHERE id IN (SELECT DISTINCT (saleprice, saledate), id, count(id)
             FROM sales
             HAVING count = 1)

لكن عقلي يؤلمني أن أذهب إلى أبعد من ذلك.

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

المحلول

SELECT DISTINCT a,b,c FROM t

يكون بقسوة أي ما يعادل:

SELECT a,b,c FROM t GROUP BY a,b,c

إنها فكرة جيدة أن تعتاد على بناء جملة GROUP BY، لأنها أكثر قوة.

بالنسبة لاستفسارك، سأفعل ذلك على النحو التالي:

UPDATE sales
SET status='ACTIVE'
WHERE id IN
(
    SELECT id
    FROM sales S
    INNER JOIN
    (
        SELECT saleprice, saledate
        FROM sales
        GROUP BY saleprice, saledate
        HAVING COUNT(*) = 1 
    ) T
    ON S.saleprice=T.saleprice AND s.saledate=T.saledate
 )

نصائح أخرى

إذا قمت بتجميع الإجابات حتى الآن، وقمت بالتنظيف والتحسين، فسوف تصل إلى هذا الاستعلام المتميز:

UPDATE sales
SET    status = 'ACTIVE'
WHERE  (saleprice, saledate) IN (
    SELECT saleprice, saledate
    FROM   sales
    GROUP  BY saleprice, saledate
    HAVING count(*) = 1 
    );

الذي كثيراً أسرع من أي منهما.تعمل الأسلحة النووية على تحسين أداء الإجابة المقبولة حاليًا بعامل 10 - 15 (في اختباراتي على PostgreSQL 8.4 و9.1).

لكن هذا لا يزال بعيدًا عن المستوى الأمثل.إستخدم NOT EXISTS (مضاد) شبه الانضمام للحصول على أداء أفضل. EXISTS هو SQL قياسي، وكان موجودًا إلى الأبد (على الأقل منذ PostgreSQL 7.2، قبل وقت طويل من طرح هذا السؤال) ويناسب المتطلبات المقدمة تمامًا:

UPDATE sales s
SET    status = 'ACTIVE'
WHERE  NOT EXISTS (
   SELECT FROM sales s1                     -- SELECT list can be empty for EXISTS
   WHERE  s.saleprice = s1.saleprice
   AND    s.saledate  = s1.saledate
   AND    s.id <> s1.id                     -- except for row itself
   )
AND    s.status IS DISTINCT FROM 'ACTIVE';  -- avoid empty updates. see below

ديسيبل <> كمان هنا
كمان SQL القديم

مفتاح فريد لتحديد الصف

إذا لم يكن لديك مفتاح أساسي أو فريد للجدول (id في المثال)، يمكنك استبداله بعمود النظام ctid لغرض هذا الاستعلام (ولكن ليس لبعض الأغراض الأخرى):

   AND    s1.ctid <> s.ctid

يجب أن يكون لكل جدول مفتاح أساسي.قم بإضافة واحدة إذا لم يكن لديك واحدة حتى الآن.أقترح أ serial أو IDENTITY العمود في Postgres 10+.

متعلق ب:

كيف يتم هذا بشكل أسرع؟

الاستعلام الفرعي في EXISTS يمكن لـ anti-semi-join التوقف عن التقييم بمجرد العثور على الخدعة الأولى (لا فائدة من البحث أكثر).بالنسبة للجدول الأساسي الذي يحتوي على عدد قليل من التكرارات، يعد هذا أكثر كفاءة بشكل طفيف.مع الكثير من التكرارات يصبح هذا طريق أكثر فعالية.

استبعاد التحديثات الفارغة

للصفوف التي لديها بالفعل status = 'ACTIVE' لن يغير هذا التحديث أي شيء، ولكنه سيستمر في إدراج إصدار صف جديد بالتكلفة الكاملة (تنطبق استثناءات بسيطة).عادة، أنت لا تريد هذا.أضف آخر WHERE الشرط كما هو موضح أعلاه لتجنب ذلك وجعله أسرع:

لو status ويعرف NOT NULL, ، يمكنك التبسيط إلى:

AND status <> 'ACTIVE';

اختلاف دقيق في التعامل مع NULL

هذا الاستعلام (على عكس الإجابة المقبولة حاليًا من جويل) لا يتعامل مع القيم NULL على أنها متساوية.الصفين التاليين ل (saleprice, saledate) يمكن وصفه بأنه "متميز" (على الرغم من أنه يبدو مطابقًا للعين البشرية):

(123, NULL)
(123, NULL)

يمر أيضًا في فهرس فريد وفي أي مكان آخر تقريبًا، نظرًا لأن القيم NULL لا يمكن مقارنتها بالتساوي وفقًا لمعيار SQL.يرى:

أوتوه، GROUP BY, DISTINCT أو DISTINCT ON () معاملة القيم NULL على قدم المساواة.استخدم نمط استعلام مناسبًا اعتمادًا على ما تريد تحقيقه.لا يزال بإمكانك استخدام هذا الاستعلام الأسرع مع IS NOT DISTINCT FROM بدلاً من = لأي أو كل المقارنات لجعل المقارنة NULL متساوية.أكثر:

إذا تم تعريف جميع الأعمدة التي تتم مقارنتها NOT NULL, ، فلا مجال للخلاف.

المشكلة في الاستعلام الخاص بك هي أنه عند استخدام جملة GROUP BY (والتي تفعلها بشكل أساسي باستخدام مميز)، يمكنك فقط استخدام الأعمدة التي تقوم بتجميعها حسب الوظائف أو تجميعها.لا يمكنك استخدام معرف العمود نظرًا لاحتمال وجود قيم مختلفة.في حالتك، هناك دائمًا قيمة واحدة فقط بسبب عبارة HAVING، ولكن معظم أنظمة إدارة قواعد البيانات RDB ليست ذكية بما يكفي للتعرف على ذلك.

ومع ذلك، يجب أن يعمل هذا (ولا يحتاج إلى صلة):

UPDATE sales
SET status='ACTIVE'
WHERE id IN (
  SELECT MIN(id) FROM sales
  GROUP BY saleprice, saledate
  HAVING COUNT(id) = 1
)

يمكنك أيضًا استخدام MAX أو AVG بدلاً من MIN، ومن المهم فقط استخدام دالة تُرجع قيمة العمود إذا كان هناك صف واحد مطابق فقط.

أريد تحديد القيم المميزة من عمود واحد "GrondOfLucht" ولكن يجب فرزها بالترتيب كما هو موضح في عمود "الفرز".لا يمكنني الحصول على القيم المميزة لعمود واحد فقط باستخدام

Select distinct GrondOfLucht,sortering
from CorWijzeVanAanleg
order by sortering

سيعطي العمود أيضًا "فرزًا" ولأن "GrondOfLucht" و"الفرز" ليسا فريدين، ستكون النتيجة جميع الصفوف.

استخدم المجموعة لتحديد سجلات "GrondOfLucht" بالترتيب المعطى بواسطة "الفرز"

SELECT        GrondOfLucht
FROM            dbo.CorWijzeVanAanleg
GROUP BY GrondOfLucht, sortering
ORDER BY MIN(sortering)

إذا كان نظام إدارة قواعد البيانات لديك لا يدعم أعمدة متعددة مثل هذا:

select distinct(col1, col2) from table

يمكن تنفيذ التحديد المتعدد بشكل عام بأمان كما يلي:

select distinct * from (select col1, col2 from table ) as x

نظرًا لأن هذا يمكن أن يعمل على معظم أنظمة إدارة قواعد البيانات ومن المتوقع أن يكون هذا أسرع من التجميع حسب الحل لأنك تتجنب وظيفة التجميع.

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