سؤال

لدي بيانات تبدو كالتالي:

entities
id         name
1          Apple
2          Orange
3          Banana

بشكل دوري، سيتم تشغيل العملية وإعطاء درجة لكل كيان.تقوم العملية بإنشاء البيانات وإضافتها إلى جدول النتائج كما يلي:

scores 
id  entity_id    score   date_added
1    1            10       1/2/09
2    2            10       1/2/09
3    1            15       1/3/09
4    2            10       1/03/09
5    1            15       1/4/09
6    2            15       1/4/09
7    3            22       1/4/09

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

entities
id name     score  date_added
1  Apple     15     1/4/09
2  Orange    15     1/4/09
3  Banana    15     1/4/09

يمكنني الحصول على بيانات كيان واحد باستخدام هذا الاستعلام:

SELECT entities.*, 
       scores.score, 
       scores.date_added 
FROM entities

INNER  JOIN scores
ON entities.id = scores.entity_id

WHERE entities.id = ?

ORDER BY scores.date_added DESC
LIMIT 1

لكنني في حيرة من أمري بشأن كيفية اختيار نفس الشيء لجميع الكيانات.ربما يحدق في وجهي؟

شكرا جزيلا لأخذ الوقت.

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

تحديث:لقد جربت العديد من الحلول المقترحة، والمشكلة الرئيسية التي أواجهها الآن هي أنه إذا لم يكن لدى الكيان بعد نتيجة تم إنشاؤها، فلن يظهر في القائمة.

كيف سيبدو SQL لضمان إرجاع جميع الكيانات، حتى لو لم يتم نشر أي نتيجة لها بعد؟

تحديث:تم تحديد الإجابة.شكرا لكم جميعا!

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

المحلول

وأفعل ذلك بهذه الطريقة:

SELECT e.*, s1.score, s1.date_added 
FROM entities e
  INNER JOIN scores s1
    ON (e.id = s1.entity_id)
  LEFT OUTER JOIN scores s2
    ON (e.id = s2.entity_id AND s1.id < s2.id)
WHERE s2.id IS NULL;

نصائح أخرى

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

SELECT e.*, s1.score
FROM entities e
INNER JOIN score s1 ON e.id = s1.entity_id
WHERE NOT EXISTS (
    SELECT 1 FROM score s2 WHERE s2.id > s1.id
)

النهج 1

SELECT entities.*, 
       scores.score, 
       scores.date_added 
FROM entities

INNER  JOIN scores
ON entities.id = scores.entity_id

WHERE scores.date_added = 
  (SELECT max(date_added) FROM scores where entity_id = entities.id)

النهج 2

تكلفة الاستعلام بالنسبة للدُفعة:


SELECT entities.*, 
       scores.score, 
       scores.date_added 
FROM entities

INNER  JOIN scores
ON entities.id = scores.entity_id

inner join 
    (
    SELECT 
           entity_id, max(date_added) as recent_date
    FROM scores
    group by entity_id
    ) as y on entities.id = y.entity_id and scores.date_added = y.recent_date

وأعرف أن هذا هو السؤال القديم، بس كنت أضيف نهجا وقد ذكر لا أحد حتى الآن، Cross Apply أو Outer Apply. هذه متوفرة في SQL Server 2005 (لم يتم وضع علامة على نوع قاعدة البيانات في هذا السؤال) أو أعلى

وباستخدام الجداول المؤقتة

DECLARE @Entities TABLE(Id INT PRIMARY KEY, name NVARCHAR(MAX))
INSERT INTO @Entities
VALUES (1, 'Apple'), (2, 'Orange'), (3, 'Banana'), (4, 'Cherry')

DECLARE @Scores TABLE(Id INT PRIMARY KEY, Entity_Id INT, Score INT, Date_Added DATE)
INSERT INTO @Scores
VALUES (1,1,10,'2009-02-01'),
(2,2,10,'2009-02-01'),
(3,1,15,'2009-02-01'),
(4,2,10,'2009-03-01'),
(5,1,15,'2009-04-01'),
(6,2,15,'2009-04-01'),
(7,3,22,'2009-04-01')

هل يمكن استخدام

SELECT E.Id, E.name, S.Score, S.Date_Added 
FROM @Entities E
CROSS APPLY
(
    SELECT TOP 1 * 
    FROM @Scores Sc 
    WHERE Sc.Entity_Id = E.Id  
    ORDER BY sc.Score DESC
) AS S

للحصول على النتائج المرجوة. وequivilent للسماح أن الكيانات دون عشرات يكون

SELECT E.Id, E.name, S.Score, S.Date_Added 
FROM @Entities E
OUTER APPLY
(
    SELECT TOP 1 * 
    FROM @Scores Sc 
    WHERE Sc.Entity_Id = E.Id  
    ORDER BY sc.Score DESC
) AS S
SELECT entities.*, 
       scores.score, 
       scores.date_added 
FROM entities

INNER  JOIN scores
ON entities.id = scores.entity_id

WHERE entities.id in 
(select id from scores s2 where date_added = max(date_added) and s2.id = entities.id)

ORDER BY scores.date_added DESC
LIMIT 1

يمكنك أيضًا القيام بذلك اليوم في معظم أنظمة RDBMS (Oracle وPostgreSQL وSQL Server) باستخدام استعلام طبيعي باستخدام وظائف النافذة مثل ROW_NUMBER:

SELECT id, name, score, date_added FROM (
 SELECT e.id, e.name, s.score, s.date_added,
 ROW_NUMBER() OVER (PARTITION BY e.id ORDER BY s.date_added DESC) rn
 FROM Entities e INNER JOIN Scores s ON e.id = s.entity_id
) tmp WHERE rn = 1;

SQL كمان

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