-
אני מנסה להגדיר את השאלה שלי, מקווה שתבינו אותה.
נניח יש לי חנות, ולקוחות מזמינים כל חודש סחורה.
לצורך הענין בשלש חודשים ראשונים של השנה:
ראובן הזמין ב10 20 30
שמעון 100 200 300
לוי 1000 2000 3000אני רוצה לעשות שאילתא שתציג טבלא אחת שיראו בבירור כל לקוח כמה הזמין לפי חודש
בציר הX יראו שמות של לקוחות, בציר הY חודשים, וכבונוס בקצוות יהיה רשום כמה סה"כ כל לקוח הזמין, וכמה הוזמן סה"כ בכל חודש.התחלתי בשלב ראשון לכתוב שאילתא כזו לבד, לשלשת הלקוחות האלה
http://sqlfiddle.com/#!9/11e8be/11/0
אבל משום מה זה מחזיר תשובה רק על ראובן. אני מפספס משהו ולא תופס מה זה.כשלב שני, אני מחפש איך להכין פונקציה בMYSQL (עם שילוב של PHP אני יודע לעשות, אבל יש לי ענין שיהיה דווקא בMYSQL, אסביר אחר כך למה), שתכין את הטבלא הזו לכל הלקוחות בטבלא, דהיינו בלי שיהיה כתוב במפורש בשאילתא למיין לפי השם של הלקוח פלוני ואלמוני.
המטרה היא בניית ממשק ניהול מסוים, שמבוסס על PHPMYADMIN, תוך שימוש בBOOKMARK של PMA, מה שחוסך הצורך להקים ממשק מההתחלה. ב"ה זה פחות או יות מוכן, ואני רוצה לשכלל את זה עם הטבלא הנ"ל.
תודה רבה -
אני ינסה לענות מה שנראה לי אני לא כל כך מבין בזה,(אל תסמוך עליי להלכה.) אבל לפחות יהיה לך עוד כיוון חשיבה.
כשאתה מדפיס את התוצאה של השאילתה הוא מדפיס לפי הערך monthYear ומציג ערך אחד בלבד ששווה ל 01-2022 למשל יציג לך רק את ראובן ב 01-2022 כי הוא כבר הדפיס משהו מ 01-2022.
ולכן לדוגמא אם תמחוק את ההכנסה של הנתונים של ראובן של 01-2022 ותדפיס תראה שפתאום את שמעון הוא גם מדפיס. (את 01-2022)
כלומר כשאתה ממין לפי הערך הזה הוא ידפיס רק אחד מכל ערך.
לסיכום, נראה ש GROUP BY monthYear
מכניס לקבוצה רק ערך אחד מכל סוג ולא את הכל. -
התחביר הנכון הוא כך:
SELECT monthYear, SUM(CASE WHEN name = 'REOUVEN' THEN price END) AS REOUVEN, SUM(CASE WHEN name = 'SHIMON' THEN price END) AS SHIMON, SUM(CASE WHEN name = 'LEVI' THEN price END) AS LEVI FROM AZMANOT GROUP BY monthYear ORDER BY monthYear DESC;
-
@OdedDvir יישר כוח. לא ידעתי שיש חילוק בין IF וCASE.
העברתי לMYSQL 8 וזה גם עובד נהדר, כנראה שיש הבדל מהותי יותר עם CASE שתופס על GROUP.
https://www.db-fiddle.com/f/75xSbAmhsC5wbDhfxTDxcR/1עכשיו לשאלה השניה.
מה הצורה הנכונה להכין שאילתא אוטומטית, שגם אם יהיו עשר לקוחות, זה יכין את הטבלא הזו בצורה נכונה.
תודה רבה! -
הנה דוגמה מצויינת למה היכולת של MYSQL להשמיט פונקציית צבירה בפירוש מביא לבאגים (https://tchumim.com/topic/13246, ואם להיות ספציפי למי שנראה לי מעניין אותו זה @יוסף-בן-שמעון).
@שואף, התיקון לבעיה שלך איננו ההבדל בין IF לבין CASE (אין לי מושג למה @OdedDvir על הדרך שיפר את זה עבור MSSQL).
הנקודה היא שלא עטפת את הIF בSUM.
ובשביל להבין מה הבעיה צריך פשוט להוריד את הGROUP BY ואז הבעיה בולטת לעיניים:
יש לנו שורה לכל קניה, ובשורה הראשונה הקניה היא של REUVEN ולכן הסכום שמה בREUVEN יהיה סכום הקניה, אולם העמודות של שמעון ולוי יהיו 1. מה קורה בעת הקיבוץ? כל שלושת השורות של חודש מסויים הופכים לשורה אחת. ואיזה ערך יופיע בכל אחד מהעמודות? אז איפה שצויין SUM, יופיע סיכום. איפה שלא, יילקח הערך של השורה הראשונה של הקבוצה... קרי השורה של REUVEN. -
@שואף אתה בעצם מבקש ליצור טבלת ציר. לא ידוע לי שיש פונקציית
PIVOT
ב-MySQL, לכן צריך להתחכם ולשרשר כמה משפטיCASE
ברצף.
כדי לקבל את שם העמודה בכל פעם, יש ליצור את נוסח המשפט באופן דינמי עבור כל ערך, ואז להשתמש בGROUP_CONCAT
:SET @sql = NULL; SELECT GROUP_CONCAT(DISTINCT CONCAT( 'SUM(CASE WHEN name = "', name, '" THEN price ELSE 0 END) AS ', name) ) INTO @sql FROM AZMANOT; SET @sql = CONCAT('SELECT monthYear, ', @sql, ' FROM AZMANOT GROUP BY monthYear'); SELECT @sql; PREPARE t FROM @sql; EXECUTE t; DEALLOCATE PREPARE t;
-
@dovid אמר במסד נתונים כטבלא בשני ממדים:
אין לי מושג למה @OdedDvir על הדרך שיפר את זה עבור MSSQL
צודק, בראש הקודח שלי תקוע ש-CASE עדיף מ-IF, (אאל"ט בגלל שהוא תומך ב Short-Circuting), אבל כאן זה לכאורה לא משנה, ואפשר לכתוב גם כך:
SUM(IF(name = 'REOUVEN', price, 0)) AS REOUVEN, ...
-
@OdedDvir תודה רבה מאוד! ישבתי ללמוד את השאילתא שלך, יש בה כמה אלמנטים שלא הכרתי.
תרשה לי לשאול כמה שאלות.
א. למה השורה הראשונה? ענין של תקינות?SET @sql = NULL;
ב. למה כתבת בשורה הרביעית ELSE 0 ? מה היה חסר בלי זה?
ג. שורה 11 כתבת SELECT @sql; כנ"ל זה היה נחוץ, או רק בשביל הדיבגינג?
שוב תודה.
-
@שואף למרות שהקוד לכאורה יעבוד גם בלי התוספות האלו, כתבתי שלענ"ד זה עניין של הרגלים טובים. הללו נועדו כדי למנוע בעיות בעתיד, כשכבר הספקת לשכוח פעמיים מה כתבת כאן בקוד, ואתה מוצא את עצמך מחפש בנרות את הבעיה.
זה הדברים הקטנים האלו בתכנות שעלולים לגרום בעיות גדולות בהמשך.
דוגמא משעשעת לכך היא הטעות שהשתרבבה לגוגל באחד העדכונים ל ChromeOS, וגרמה לאלפי משתמשים להנעל מחוץ לחשבון שלהם.
הטעות היתה בהשמטת תו אחד בודד בבדיקה של סיסמת המשתמש בתנאיif
, בו בטעות השתמשו באופרטור הבינארי&
במקום באופרטור הלוגי&&
.
דהיינו כתבו:if (key_data_.has_value() & !key_data_->label().empty()) {
במקום
if (key_data_.has_value() && !key_data_->label().empty()) {
מה שגרם להחזרה של ערך
false
גם במקרה של סיסמה נכונה, ולהציג למשתמש את ההודעה ש"אנו מצטערים, אבל לא הצלחנו לאמת את סיסמתך." -
@אפר-שריפה אמר במסד נתונים כטבלא בשני ממדים:
@שואף נראה לי שזה הרבה יותר רלוונטי אליך
https://stackoverflow.com/questions/15931607/convert-rows-to-columns-using-pivot-in-sql-serverאולי התכוונת לזה - https://stackoverflow.com/questions/7674786/how-can-i-return-pivot-table-output-in-mysql
יש שם כמה פתרונות...
-