سؤال

خذ بعين الاعتبار أوراكل emp طاولة.أرغب في الحصول على الموظفين ذوي الرواتب الأعلى department = 20 و job = clerk.افترض أيضًا أنه لا يوجد عمود "empno"، وأن المفتاح الأساسي يتضمن عددًا من الأعمدة.يمكنك القيام بذلك باستخدام:

select * from scott.emp
where deptno = 20 and job = 'CLERK'
and sal =  (select max(sal) from scott.emp
            where deptno = 20 and job = 'CLERK')

يعمل هذا، ولكن لا بد لي من تكرار قسم الاختبار = 20 والوظيفة = 'CLERK'، وهو ما أود تجنبه.هل هناك طريقة أكثر أناقة لكتابة هذا، ربما باستخدام ملف group by؟راجع للشغل، إذا كان هذا مهمًا، فأنا أستخدم Oracle.

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

المحلول

تم تصميم ما يلي بشكل مبالغ فيه بعض الشيء، ولكنه نموذج SQL جيد لاستعلامات "top x".

SELECT 
 * 
FROM 
 scott.emp
WHERE 
 (deptno,job,sal) IN
 (SELECT 
   deptno,
   job,
   max(sal) 
  FROM 
   scott.emp
  WHERE 
   deptno = 20 
   and job = 'CLERK'
  GROUP BY 
   deptno,
   job
  )

لاحظ أيضًا أن هذا سيعمل في Oracle وPostgress (على ما أظن) ولكن ليس في MS SQL.للحصول على شيء مماثل في MS SQL، راجع السؤال استعلام SQL للحصول على أحدث الأسعار

نصائح أخرى

إذا كنت متأكدًا من قاعدة البيانات المستهدفة، فسأختار حل Mark Nold، ولكن إذا كنت تريد بعض SQL* المحايدة للهجة، فحاول

SELECT * 
FROM scott.emp e
WHERE e.deptno = 20 
AND e.job = 'CLERK'
AND e.sal = (
  SELECT MAX(e2.sal) 
  FROM scott.emp e2
  WHERE e.deptno = e2.deptno 
  AND e.job = e2.job
)

*أعتقد أن هذا يجب أن ينجح في كل مكان، ولكن ليس لدي البيئات اللازمة لاختباره.

في Oracle، سأفعل ذلك باستخدام وظيفة تحليلية، لذلك يمكنك الاستعلام عن جدول emp مرة واحدة فقط:

SELECT *
  FROM (SELECT e.*, MAX (sal) OVER () AS max_sal
          FROM scott.emp e
         WHERE deptno = 20 
           AND job = 'CLERK')
 WHERE sal = max_sal

إنها أبسط وأسهل في القراءة وأكثر كفاءة.

إذا كنت تريد تعديلها لسرد هذه المعلومات لجميع الأقسام، فسوف تحتاج إلى استخدام عبارة "PARTITION BY" في OVER:

SELECT *
  FROM (SELECT e.*, MAX (sal) OVER (PARTITION BY deptno) AS max_sal
          FROM scott.emp e
         WHERE job = 'CLERK')
 WHERE sal = max_sal
ORDER BY deptno

ذلك رائع!لم أكن أعلم أنه يمكنك إجراء مقارنة بين (x، y، z) مع نتيجة عبارة SELECT.هذا يعمل بشكل رائع مع أوراكل.

كملاحظة جانبية للقراء الآخرين، يفتقد الاستعلام أعلاه "=" بعد "(deptno,job,sal)".ربما أكله منسق Stack Overflow (؟).

مرة أخرى، شكرا مارك.

في Oracle، يمكنك أيضًا استخدام عبارة EXISTS، والتي تكون أسرع في بعض الحالات.

على سبيل المثال...حدد اسمًا ، رقمًا من CUST WHERE CUST (حدد CUST_ID من Big_table) وسيكون Sysdate -1 بطيئًا.

لكن حدد الاسم ، الرقم من الحجز جحيث يوجد (حدد cust_id من big_table حيث cust_id=c.cust_id ) ودخول> sysdate -1 سيكون سريعًا جدًا مع الفهرسة المناسبة.يمكنك أيضًا استخدام هذا مع معلمات متعددة.

هناك العديد من الحلول.يمكنك أيضًا الاحتفاظ بتخطيط الاستعلام الأصلي الخاص بك عن طريق إضافة الأسماء المستعارة للجدول والانضمام إلى أسماء الأعمدة، وسيظل لديك فقط DEPTNO = 20 وJOB = 'CLERK' في الاستعلام مرة واحدة.

SELECT 
  * 
FROM 
  scott.emp emptbl
WHERE
  emptbl.DEPTNO = 20 
  AND emptbl.JOB = 'CLERK'
  AND emptbl.SAL =  
    (
      select 
        max(salmax.SAL) 
      from 
        scott.emp salmax
      where 
        salmax.DEPTNO = emptbl.DEPTNO
        AND salmax.JOB = emptbl.JOB
    )

ويمكن أيضًا ملاحظة أنه يمكن استخدام الكلمة الأساسية "ALL" لهذه الأنواع من الاستعلامات والتي قد تسمح لك بإزالة وظيفة "MAX".

SELECT 
  * 
FROM 
  scott.emp emptbl
WHERE
  emptbl.DEPTNO = 20 
  AND emptbl.JOB = 'CLERK'
  AND emptbl.SAL >= ALL  
    (
      select 
        salmax.SAL
      from 
        scott.emp salmax
      where 
        salmax.DEPTNO = emptbl.DEPTNO
        AND salmax.JOB = emptbl.JOB
    )

آمل أن يساعد ذلك ويكون منطقيًا.

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