سؤال

لدي هذا releases جدول في قاعدة بيانات SQLite3، يسرد كل إصدار تم إصداره من التطبيق:

|release_id|release_date|app_id|
|==========|============|======|
|      1001| 2009-01-01 |     1|
|      1003| 2009-01-01 |     1|
|      1004| 2009-02-02 |     2|
|      1005| 2009-01-15 |     1|

لذا، سيكون هناك صفوف متعددة لكل app_id.عندي طاولة اخرى apps:

|app_id|name    |
|======|========|
|     1|Everest |
|     2|Fuji    |

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

يمكنني القيام بذلك لتطبيق فردي:

SELECT apps.name,releases.release_id,releases.release_date 
  FROM apps 
  INNER JOIN releases 
    ON apps.app_id = releases.app_id
  WHERE releases.release_id = 1003
  ORDER BY releases.release_date,releases.release_id
  LIMIT 1

ولكن بالطبع ينطبق ذلك ORDER BY على استعلام SELECT بالكامل، وإذا تركت جملة WHERE، فإنها لا تزال تُرجع صفًا واحدًا فقط.

إنه استعلام يتم تنفيذه مرة واحدة على قاعدة بيانات صغيرة، لذا فإن الاستعلامات البطيئة والجداول المؤقتة وما إلى ذلك.بخير - لا أستطيع أن أركز تفكيري على طريقة SQL للقيام بذلك.

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

المحلول

وهذا من السهل القيام به مع ROW_NUMBER الدوال التحليلية ()، والتي أعتقد sqlite3 لا يدعم. ولكن يمكنك أن تفعل ذلك بطريقة قليلا أكثر مرونة مما يعطى في الأجوبة السابقة:

SELECT
  apps.name,
  releases.release_id,
  releases.release_date 
FROM apps INNER JOIN releases 
ON apps.app_id = releases.app_id
WHERE NOT EXISTS (
-- // where there doesn't exist a more recent release for the same app
  SELECT * FROM releases AS R
  WHERE R.app_id = apps.app_id
  AND R.release_data > releases.release_data
)

وعلى سبيل المثال، إذا كان لديك العديد من الأعمدة التي تحدد ترتيب "آخر"، MAX لن تعمل من أجلك، ولكن هل يمكن تعديل المشرقية فرعي للقبض على معنى أكثر تعقيدا من "تقدير".

نصائح أخرى

هذه هي مشكلة "أكبر N لكل مجموعة".يتم طرحه عدة مرات في الأسبوع على StackOverflow.

عادةً ما أستخدم حلاً مثل ذلك الموجود في @Steve Kass' إجابة, ، لكنني أفعل ذلك بدون استعلامات فرعية (اعتدت على MySQL 4.0 منذ سنوات مضت، والذي لم يكن يدعم الاستعلامات الفرعية):

SELECT a.name, r1.release_id, r1.release_date
FROM apps a
INNER JOIN releases r1
LEFT OUTER JOIN releases r2 ON (r1.app_id = r2.app_id 
  AND (r1.release_date < r2.release_date
    OR r1.release_date = r2.release_date AND r1.release_id < r2.release_id))
WHERE r2.release_id IS NULL;

داخليًا، ربما يكون هذا هو الأمثل بشكل مماثل لـ NOT EXISTS بناء الجملة.يمكنك تحليل الاستعلام باستخدام EXPLAIN للتأكد.


إعادة تعليقك، يمكنك فقط تخطي الاختبار ل release_date لأن release_id مفيد أيضًا في إنشاء الترتيب الزمني للإصدارات، وأفترض أنه من المضمون أن يكون فريدًا، لذلك فإن هذا يبسط الاستعلام:

SELECT a.name, r1.release_id, r1.release_date
FROM apps a
INNER JOIN releases r1
LEFT OUTER JOIN releases r2 ON (r1.app_id = r2.app_id 
  AND r1.release_id < r2.release_id)
WHERE r2.release_id IS NULL;

وانها قبيحة، ولكن أعتقد أنه سوف يعمل

select apps.name, (select releases.release_id from releases where releases.app_id=apps.app_id order by releases.release_date, releases.release_id), (select releases.release_date from releases where releases.app_id=apps.app_id order by releases.release_date, releases.release_id) from apps order by apps.app_id

وآمل أن هناك طريقة للحصول على كل من هذه الأعمدة في واحدة جزءا لا يتجزأ من اختيار، ولكن أنا لا أعرف ذلك.

وجرب:

SELECT a.name,
       t.max_release_id,
       t.max_date
  FROM APPS a
  JOIN (SELECT t.app_id,
               MAX(t.release_id) 'max_release_id',
               t.max_date
          FROM (SELECT r.app_id,
                       r.release_id,
                       MAX(r.release_date) 'max_date'
                  FROM RELEASES r
              GROUP BY r.app_id, r.release_id)
      GROUP BY t.app_id, t.max_date) t

وخطأ المحاولة الثانية. على افتراض أن معرفات تتزايد مفردة النغمة وتجاوز ليست حدوثها المحتمل، يمكنك تجاهل التاريخ ومجرد القيام:

SELECT apps.name, releases.release_id, releases.release_date 
FROM apps INNER JOIN releases on apps.app_id = releases.app_id
WHERE releases.release_id IN 
(SELECT Max(release_id) FROM releases
GROUP BY app_id);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top