هل يمكن تبسيط استعلام SQL هذا؟
سؤال
لدي الجداول التالية:
الشخص ، {"id" ، "name" ، "lastName"}
Sports ، {"id" "name" ، "type"}
Sportsperperson ، {"id" ، "personid" ، "SportsId"}
بالنسبة لاستعلامي ، أريد أن أحصل على جميع الأشخاص الذين يبررون رياضة محددة في حين أن لدي فقط سمة "الاسم" الرياضية تحت تصرفي. لاسترداد الصفوف الصحيحة ، اكتشفت الاستعلامات التالية:
SELECT *
FROM Person
WHERE Person.Id in
(
SELECT SportsPerPerson.PersonId FROM SportsPerPerson
INNER JOIN Sports on SportsPerPerson.SportsId = Sports.Id
WHERE Sports.Name = 'Tennis'
)
AND Person.Id in
(
SELECT SportsPerPerson.PersonId FROM SportsPerPerson
INNER JOIN Sports on SportsPerPerson.SportsId = Sports.Id
WHERE Sports.Name = 'Soccer'
)
أو
SELECT *
FROM Person
WHERE Id IN
(SELECT PersonId FROM SportsPerPerson WHERE SportsId IN
(SELECT Id FROM Sports WHERE Name = 'Tennis'))
AND Id IN
(SELECT PersonId FROM SportsPerPerson WHERE SportsId IN
(SELECT Id FROM Sports WHERE Name = 'Soccer'))
الآن سؤالي هو ، أليس هناك طريقة أسهل لكتابة هذا الاستعلام؟ استخدام فقط أو لن يعمل لأنني بحاجة إلى الشخص الذي يلعب "تنس" و "كرة قدم". ولكن باستخدام ولا يعمل أيضًا لأن القيم ليست على نفس الصف.
المحلول
يجب عليك استخدام اثنين من الندوات في الاستعلام:
SELECT *
FROM Person p INNER JOIN SportsPerPerson spp1 ON (p.PersonId = spp1.PersonId)
INNER JOIN Sports s1 ON (s1.SportsIN = spp1.SportId)
INNER JOIN SportsPerPerson spp2 ON (p.PersonId = spp2.PersonId)
INNER JOIN Sports s2 ON (s2.SportId = spp2.SportId)
WHERE s1.Name = 'Tennis' AND s2.Name='Soccer'
نصائح أخرى
يمكنك استخدام آخر JOIN
لتجنب الثانية IN
. يعيد المجموعة الفرعية فقط هؤلاء الأشخاص الذين يلعبون كل من التنس وكرة القدم:
SELECT *
FROM Person
WHERE Person.Id IN
(
SELECT spp1.PersonId
FROM SportsPerPerson spp1
JOIN SportsPerPerson spp2 ON ( spp2.PersonId = spp1.PersonId )
JOIN Sports s1 on spp1.SportsId = s1.Id
JOIN Sports s2 on spp2.SportsId = s2.Id
WHERE s1.Name = 'Tennis'
AND s2.Name = 'Soccer'
)
الحيلة هي استخدام الأسماء المستعارة حتى تتمكن من استخدام الجداول نفسها عدة مرات:
SELECT p.*
FROM Person p
INNER JOIN SportsPerPerson spa
ON p.Id = spa.PersonId
INNER JOIN Sports sa
ON spa.SportsId = sa.Id
INNER JOIN SportsPerPerson spb
ON p.Id = spb.PersonId
INNER JOIN Sports sb
ON spb.SportsId = sb.Id
WHERE
sa.Name = 'Tennis'
AND sb.Name = 'Soccer'
هذه:
SELECT *
FROM Person p
WHERE (
SELECT COUNT(*)
FROM Sports s
JOIN SportsPerPerson sp
ON sp.SportsID = s.id
WHERE s.name IN ('Tennis', 'Soccer')
AND sp.PersonID = p.id
) = 2
أو هذا:
SELECT p.*
FROM (
SELECT sp.PersonID
FROM Sports s
JOIN SportsPerPerson sp
ON sp.SportsID = s.id
WHERE s.name IN ('Tennis', 'Soccer')
GROUP BY
sp.PersonID
HAVING COUNT(*) = 2
) q
JOIN person p
ON p.id = q.personID
تحتاج إلى إعلان أ UNIQUE KEY
أو أ PRIMARY KEY
تشغيل SportsPerPerson (sportsid, personid)
لهذا العمل بشكل صحيح وسريع.
الاستعلام الذي تحتاجه هو:
SELECT p.ID, p.Name, p.LastName
FROM Person p
JOIN SportsPerPerson sp ON p.ID = sp.PersonID
JOIN Sports s ON sp.SportsID = s.ID
WHERE s.Name = 'Football'
ومع ذلك ، جانبا ، مفتاح المعرف على طاولة SportsPerperson ليس من الضروري تمامًا تنفيذ العديد من العلاقات التي لديك. سيكون استخدام الأعمدة الشخصية والرياضية كمفتاح أساسي مركب كافيًا.