tannenbaum: MySQL & Left Join, wieso nicht alle Datensätze?

Hi!

hier zuerst mal der relevante teil der DB:
----------
CREATE TABLE users (uid bigint(20) unsigned NOT NULL default '0', vid int(10) unsigned NOT NULL default '0',oid tinyint(3) unsigned NOT NULL default '0',ip varchar(15) NOT NULL default '',PRIMARY KEY  (uid,vid)) TYPE=MyISAM COMMENT='Users and Vote Table';
CREATE TABLE vote (vid int(10) unsigned NOT NULL auto_increment,name varchar(200) NOT NULL default '',PRIMARY KEY  (vid),UNIQUE KEY name (name)) TYPE=MyISAM COMMENT='Main Vote Table' AUTO_INCREMENT=8 ;
CREATE TABLE vote\_option (vid int(10) unsigned NOT NULL default '0', oid tinyint(3) unsigned NOT NULL default '0',name varchar(200) NOT NULL default '',PRIMARY KEY  (vid,oid)) TYPE=MyISAM COMMENT='Vote options';

INSERT INTO users VALUES (101, 7, 2, '101');
INSERT INTO users VALUES (102, 7, 3, '102');
INSERT INTO users VALUES (103, 7, 3, '103');
INSERT INTO users VALUES (104, 7, 4, '104');

INSERT INTO vote\_option VALUES (7, 1, 'opt1');
INSERT INTO vote\_option VALUES (7, 2, 'opt2');
INSERT INTO vote\_option VALUES (7, 3, 'opt3');
INSERT INTO vote\_option VALUES (7, 4, 'opt4');
INSERT INTO vote\_option VALUES (7, 5, 'opt5');
----------

dann das SELECT-Query:
----------
SELECT options.oid, options.name AS name, COUNT(*) AS votes FROM BVP_vote_option options LEFT JOIN BVP_users users ON options.oid = users.oid WHERE users.vid = 7 GROUP BY users.oid ORDER BY votes DESC
----------

und das Ergebnis:
----------
3 opt3 2
4 opt4 1
2 opt2 1
----------

das Problem:
müssten es nicht 5 Datensätze sein? der LEFT-JOIN ist ja dazu da dass alles angezeigt wird, ich hätte mir als Ergebniss sowas vorgestellt:
----------
3 opt3 2
4 opt4 1
2 opt2 1
1 opt1 0
5 opt5 0
----------

weiß jemmand was da schief gelaufen ist bzw. wie ich zum gewünschten Ergebnis komme?

thx

  1. sry, hab vorhin beim db-teil eine zeile vergessen:

    INSERT INTO BVP\_vote VALUES (7, 'moo');

  2. Hi,

    ich glaube du hast Recht, aber die Datenbank leider auch. Da hast insoweit Recht, als dass rein von dem LEFT JOIN sämtliche Vote-Options rauskommen. Tun sie auch, sie sind nach dem Join tatsächlich noch übrig (behaupte ich), allerdings wendest du dann _nach_ dem JOIN ein WHERE-Kriterium an, und das haut sie raus.
    Es könnte u.U. klappen, wenn du als User-ID auch NULL erlauben würdest.

    MfG
    Rouven

    --
    -------------------
    ss:) zu:) ls:& fo:) de:< va:{ ch:? sh:) n4:( rl:? br:$ js:| ie:) fl:(
  3. yo,

    weiß jemmand was da schief gelaufen ist bzw. wie ich zum gewünschten Ergebnis komme?

    drei dinge laufen bei dir schief.

    zum einen die tabellennamen. wenn ich deine tabellen und daten eingebe, bekomme ich eine fehlermeldung, dass es die tabelle BVP_vote_option nicht gibt. und das macht auch sinn, heißen deine tabellen doch users, vote, und vote_option.

    zweitens, das dbms führt erst den LEFT JOIN aus und dann die bedingung in der WHERE klausel. dies kann zu unerwarteten ergebnissen kommen, da damit quasi der OUTER JOIN ausgehebelt wird. dies kannst du umgehen, indem du die WHERE bedingung mit in die JOIN bedingung nimmst.

    LEFT JOIN users ON (options.oid = users.oid AND users.vid = 7)

    drittens musst du mit deiner gruppierung, bzw, den spalten aufpassen, die du asugeben willst. mysql hat dort einen nicht optimalen weg eingeschlagen. grundsäzlich gilt, jede spalten die du ausgeben willst, muss auch mit in die GROUP BY klausel rein, ausgenommen sind aggregat-funktionen wie COUNT(). und daran würde ich mich auch halten, auch wenn mysql keine fehlermeldung ausgibt.

    Ilja