צפיות
תשובות
שאלת Group By מסובכת…
שלום לכולם!
איך אני יכול ב-SQL להחזיר את כל הרשומה, בה ערך מסויים הוא הכי גבוה מכל הטור שלו בטבלה?
הדוגמא:
יש לי טבלת מצעדים.
לכל מצעד, יש את התקליטן שסיפק את המצעד, ואת סגנון המצעד (לדוגמא: מצעד היפ-הופ, מצעד דאנס וכו').
לכל מצעד יש גם את התאריך שלו.
אני רוצה להציג רק את המצעדים העדכניים של כל תקליטן על כל סגנון מצעד אותו הגיש.
זאת אומרת שלכל תקליטן יכולים להיות כמה סגנונות של מצעדים, והמערכת תציג כל אחד מהם, בתנאי שהם הכי עדכניים (אם הוא הזין מצעד נוסף ישן יותר מאותו סגנון, המערכת לא תציג את המצעד הזה).
זה צריך להראות משהו כזה:
SELECT ChartDj, ChartGenre, MAX(ChartDate) FROM Charts
GROUP BY ChartDj, ChartGenre
השאילתא הזאת תחזיר לי לכל סוג מצעד של כל תקליטן, את התאריך של המצעד הכי עדכני שלו.
איך אני יכול להשתמש בנתונים האלה כדי לאחזר את שאר הנתונים לכל מצעד שהתקבל מהשאילתא?
(אני מקווה שהבנתם אותי…)
9 תשובות
אני לא כל כך בטוח שהבנתי…
למה אתה צריך עזרה…
ל group by או לשאילתה שעוקבת אחריה?
גם לא כל כך הבנתי מה בדיוק אתה רוצה לשלוף, יכול להיות שתוכל לבצע את הכל בשאילתה אחת, ללא צורך ב group by בכלל.
עם איזה מסד נתונים אתה עובד?
אני אנסה לנסח את זה אחרת…
אני עובד עם Access.
אני הייתי רוצה לנסח את הכל לשאילתא אחת, אבל אני לא מצליח להבין איך לעשות את זה.
אני לא בטוח שצריך Group By, למרות שזה נראה לי די הגיוני.
שוב בקצרה:
יש טבלה של מצעדים.
כל רשומה מכילה שם של תקליטן, סוג המצעד שסיפק, ותאריך המצעד.
לכל תקליטן יכולים להיות כמה מצעדים מסוגים שונים, ותאריכים מרובים.
אני רוצה בשאילתא אחת לשלוף את כל המצעדים הכי עדכניים.
זה אומר שעבור תקליטנים שיש להם יותר מסוג מצעד אחד, ישלפו כל המצעדים השונים שסיפקו (אבל רק בתאריכים הכי עדכניים).
דוקא ה group by יכול לעזור…
אם תשתמש ב , תוכל לבצע חיתוכים גם על התוצאה של ה group by באותה השאילתה.
משהו בסגנון הזה אמור לפתור לך את הבעיה:
SELECT ChartDj, ChartGenre, MAX(ChartDate) FROM Charts
GROUP BY ChartDj, ChartGenre
ChartDate = MAX(ChartDate)
הצלחתי… אבל איך לשדרג את הקוד?
אחרי הרבה מאוד ניסיונות, בסוף הצלחתי, וזה בזכות תת-שאילתה מתואמת (Correlated Sub-Query).
למי שרוצה לדעת איך נראית השאילתה הענקית שלי, אז היא כזאת:
SELECT Dj.DisplayName, Genres.Genre, Charts.Top10ChartGenreID, " &_
"Charts.Top10ChartID, Charts.Top10ChartDate, Charts.Top10ChartProviderID " &_
"FROM Top10Charts AS Charts, Top10ChartGenres AS Genres, AdminUsers AS Dj " &_
"WHERE Charts.Top10ChartGenreID=Genres.Top10ChartGenreID " &_
"AND Charts.Top10ChartProviderID=Dj.AdminUserID " &_
"AND EXISTS " &_
"(SELECT Top10ChartProviderID FROM " &_
"(SELECT Top10ChartProviderID, Top10ChartGenreID, MAX(Top10ChartDate) AS MaxDate " &_
"FROM Top10Charts " &_
"GROUP BY Top10ChartProviderID, Top10ChartGenreID) " &_
"WHERE Top10ChartProviderID = Charts.Top10ChartProviderID " &_
"AND Top10ChartGenreID = Charts.Top10ChartGenreID " &_
"AND MaxDate = Top10ChartDate " &_
"ORDER BY Top10ChartDate DESC, Charts.Top10ChartID DESC
הרעיון של תת-שאילתה מתואמת, הוא שהשאילתה החיצונית שולחת ערך לתוך השאילתה הפנימית, לצורך הצבת תנאי כלשהו.
במקרה הזה, השאילתה החיצונית שולחת את תאריך המצעד כדי להשוות עם התאריך המקסימלי של שאילתה פנימית שעושה את ה-Group By.
אם הערכים שווים, אז חוזר ערך מהשאילתה, ואז מתקיים התנאי WHERE EXISTS…
זאת כל התורה.
אבל אני בטוח שהיה אפשר לכתוב את הקוד יותר פשוט (כי יש לי פה 3 רמות שונות של קינון…),
אז אם מישהו יכול לחדד לי קצת את הקוד, אני אשמח לשמוע!
שלוש שאילתות מקוננות?
אני די בטוח שאפשר לעשות את זה בצורה הרבה יותר יעילה.
תעלה לכאן את המבנה של הטבלה, ונראה מה אפשר לעשות בשבילך.
המבנה של הטבלה
קודם כל – תודה!
המבנה העיקרי (השדות הרלוונטיים לפחות) הוא:
Top10Charts
—————–
Top10ChartID (מפתח ראשי של הטבלה)
Top10ChartDate (תאריך העלאת המצעד)
Top10ChartProviderID (מפתח זר של טבלה AdminUsers)
Top10ChartGenreID (מפתח זר של טבלה Top10ChartGenres)
Top10ChartGenres
————————-
Top10ChartGenreID (מפתח ראשי של הטבלה)
Genre (שם סגנון המצעד)
AdminUsers
—————
AdminUserID (מפתח ראשי של הטבלה – מפתח זר של Top10Charts)
DisplayName (שם התקליטן)
אממ…
זה כבר תלוי בדיוק במה אתה רוצה לשלוף.
אני הגעתי לשאילתה ששולפת את שם האמן, שם הסוג, והתאריך האחרון של המצעד של אותו אמן באותו הסוג. אם צריך עוד דברים, לא שלפתי אותם.
SELECT AdminUsers.DisplayName AS artist, Top10ChartGenres.Genre AS genre, MAX(Top10Charts.Top10ChartDate) AS chartDate
FROM Top10ChartGenres INNER JOIN (AdminUsers INNER JOIN Top10Charts ON AdminUsers.AdminUserID = Top10Charts.Top10ChartProviderID) ON Top10ChartGenres.Top10ChartGenreID = Top10Charts.Top10ChartGenreID
GROUP BY AdminUsers.DisplayName, Top10ChartGenres.Genre
ORDER BY Top10ChartGenres.Genre, AdminUsers.DisplayName, MAX(Top10Charts.Top10ChartDate)
החלק היפה הוא, כמו שאתה רואה, שמדובר על שאילתה בודדת.
אבל צריך עוד שדות ופה בדיוק הבעיה
השאילתה שכתבת נחמדה מאוד,
אבל ברגע שאני רוצה לשלוף עוד נתונים על המצעד, אני לא יכול.
אני צריך לשלוף גם את ה-ChartID של המצעדים שהתקבלו מהשאילתה, כדי להגיע לנתונים הרלוונטיים.
בשאילתה הכוללת Group By, אם אני אכניס את השדה ChartID ל-SELECT, אז אני לא אקבל רק את התוצאות שרציתי, אלא את כל התוצאות.
לכן, צריך למצוא דרך לקבל מתוך השאילתה רק את ה-ID של המצעדים הרלוונטיים, ופה התחילה כל הבעיה…
בסופו של דבר, התוצאה הזאת טובה רק אם הנתונים האלה מספיקים, והבעיה היא שהם לא….
אני אחזור אליך עם תשובה טובה יותר.
לא יודע אם אני אספיק היום, אבל אני אשתדל.