Wie mehrere Termine n : 1 Kurse richtig joinen?

Wie mehrere Termine n : 1 Kurse richtig joinen?

am 07.07.2006 20:53:24 von SE

Hi,

ich habe eine Tabelle mit Terminen:

CREATE TABLE `kd55`.`termine` (
`id` int(10) unsigned NOT NULL auto_increment,
`kurse_id` int(10) unsigned NOT NULL default '0',
`von` datetime NOT NULL default '0000-00-00 00:00:00',
`bis` datetime NOT NULL default '0000-00-00 00:00:00',
`beschreibung` varchar(255) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

und dazugehörige Kurse:

DROP TABLE IF EXISTS `kd55`.`kurse`;
CREATE TABLE `kd55`.`kurse` (
`id` int(10) unsigned NOT NULL auto_increment,
`titel` varchar(255) NOT NULL default '',
...
PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Ein Kurs kann einen oder mehrere Termine haben. Die Relation wird in
termine.kurse_id festgehalten. Meine Frage: Wie joine ich die beiden
Tabellen am besten (MySQL 5.0), so dass ich in meinem Join (soll eine View
werden) zwei Felder habe, die den ersten und den letzten Termin enthalten.
Ich möchte sagen können wann ein Kurs anfängt un aufhört.

Schönen Gruß
--
Sascha Ebach Digitale Wertschöpfung
Hugo-Junkers-Str. 26 50739 Köln
Tel: 0221 / 5994393 Fax: 0221 / 5994394
mailto:se@digitale-wertschoepfung.de
Web: http://www.digitale-wertschoepfung.de

Re: Wie mehrere Termine n : 1 Kurse richtig joinen?

am 09.07.2006 19:59:27 von Kai Ruhnau

Saša Ebach wrote:
> ich habe eine Tabelle mit Terminen:
>
> CREATE TABLE `kd55`.`termine` (
> `id` int(10) unsigned NOT NULL auto_increment,
> `kurse_id` int(10) unsigned NOT NULL default '0',

Warum benutzt du einen String als Default für einen INT? phpMyAdmin?
Warum benutzt du einen Wert, der in der referenzierten Tabelle
*garantiert* nicht vorkommen kann (wegen des AUTO_INCREMENTs)? phpMyAdmin?

> `von` datetime NOT NULL default '0000-00-00 00:00:00',
> `bis` datetime NOT NULL default '0000-00-00 00:00:00',

Warum setzt du ein ungültiges Datum als Default? phpMyAdmin?

> `beschreibung` varchar(255) default NULL,
> PRIMARY KEY (`id`)

Warum benutzt du InnoDB, aber nicht dessen Fähigkeiten für Fremdschlüssel?

> ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
>
> und dazugehörige Kurse:
>
> DROP TABLE IF EXISTS `kd55`.`kurse`;
> CREATE TABLE `kd55`.`kurse` (
> `id` int(10) unsigned NOT NULL auto_increment,
> `titel` varchar(255) NOT NULL default '',
> ...
> PRIMARY KEY (`id`),
> ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
>
> Ein Kurs kann einen oder mehrere Termine haben. Die Relation wird in
> termine.kurse_id festgehalten. Meine Frage: Wie joine ich die beiden
> Tabellen am besten (MySQL 5.0), so dass ich in meinem Join (soll eine
> View werden) zwei Felder habe, die den ersten und den letzten Termin
> enthalten. Ich möchte sagen können wann ein Kurs anfängt un aufhört.

Du brauchst zweimal
http://dev.mysql.com/doc/refman/5.0/en/example-maximum-colum n-group-row.html
einmal für das minimale und einmal für das maximale Datum. Diese beiden
Sub-Querys JOINst du dann anhand der `kurs_id`.

Wenn ich mich allerdings richtig erinnere, dann tut sich MySQL bei
derartigen Abfragen mit dem Optimieren ein wenig schwer.

>
> Schönen Gruß
> --
> Sascha Ebach Digitale Wertschöpfung
> Hugo-Junkers-Str. 26 50739 Köln
> Tel: 0221 / 5994393 Fax: 0221 / 5994394
> mailto:se@digitale-wertschoepfung.de
> Web: http://www.digitale-wertschoepfung.de

Dein Sigtrenner ist kaputt.

Grüße
Kai


--
This signature is left as an exercise for the reader.

Re: Wie mehrere Termine n : 1 Kurse richtig joinen?

am 09.07.2006 23:06:02 von SE

Hallo Kai,

vielen Dank für deine Antwort.

>> CREATE TABLE `kd55`.`termine` (
>> `id` int(10) unsigned NOT NULL auto_increment,
>> `kurse_id` int(10) unsigned NOT NULL default '0',
>
> Warum benutzt du einen String als Default für einen INT? phpMyAdmin?

MySQL Query Browser hat das wohl so exportiert.

> Warum benutzt du einen Wert, der in der referenzierten Tabelle
> *garantiert* nicht vorkommen kann (wegen des AUTO_INCREMENTs)? phpMyAdmin?

kurse_id sollte keinen default haben. Kann es sein, dass MySQL
Administrator den dahingepfuscht hat?

>> `von` datetime NOT NULL default '0000-00-00 00:00:00',
>> `bis` datetime NOT NULL default '0000-00-00 00:00:00',
>
> Warum setzt du ein ungültiges Datum als Default? phpMyAdmin?

Wenn die Spalte '0000-00-00 00:00:00' ist, hat das für mein CMS eine
spezielle Bedeutung.

>> `beschreibung` varchar(255) default NULL,
>> PRIMARY KEY (`id`)
>
> Warum benutzt du InnoDB, aber nicht dessen Fähigkeiten für Fremdschlüssel?

Referenzielle Integrität halte ich über Transaktionen und die Anwendung
aufrecht. Ich halte nicht sehr viel davon die Datenbank zu viel
Verantwortung übernehmen zu lassen.

>
>> ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
>>
>> und dazugehörige Kurse:
>>
>> DROP TABLE IF EXISTS `kd55`.`kurse`;
>> CREATE TABLE `kd55`.`kurse` (
>> `id` int(10) unsigned NOT NULL auto_increment,
>> `titel` varchar(255) NOT NULL default '',
>> ...
>> PRIMARY KEY (`id`),
>> ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
>>
>> Ein Kurs kann einen oder mehrere Termine haben. Die Relation wird in
>> termine.kurse_id festgehalten. Meine Frage: Wie joine ich die beiden
>> Tabellen am besten (MySQL 5.0), so dass ich in meinem Join (soll eine
>> View werden) zwei Felder habe, die den ersten und den letzten Termin
>> enthalten. Ich möchte sagen können wann ein Kurs anfängt un aufhört.
>
> Du brauchst zweimal
> http://dev.mysql.com/doc/refman/5.0/en/example-maximum-colum n-group-row.html
>
> einmal für das minimale und einmal für das maximale Datum. Diese beiden
> Sub-Querys JOINst du dann anhand der `kurs_id`.
>
> Wenn ich mich allerdings richtig erinnere, dann tut sich MySQL bei
> derartigen Abfragen mit dem Optimieren ein wenig schwer.

Ja, das denke ich mir auch. Trotzdem danke für den Hinweis. Ich glaube
jetzt mittlerweile doch, dass es besser ist zwei Felder in der kurse
Tabelle mit `start` und `ende` zu erzeugen. Das ist zwar etwas redundant
aber es macht die Queries einfacher. Vor allem, weil es für mich sehr
einfach ist diese beiden Felder bei INSERT zu ermitteln.

> Dein Sigtrenner ist kaputt.

Ah, thx, utf gemurkse in Kombination mit Thunderbird. Keine Ahnung warum
das wohl passiert.

-se

Re: Wie mehrere Termine n : 1 Kurse richtig joinen?

am 10.07.2006 09:43:44 von Thomas Rachel

Kai Ruhnau wrote:

>> ich habe eine Tabelle mit Terminen:
>>
>> CREATE TABLE `kd55`.`termine` (
>> `id` int(10) unsigned NOT NULL auto_increment,
>> `kurse_id` int(10) unsigned NOT NULL default '0',
>
> Warum benutzt du einen String als Default für einen INT? phpMyAdmin?
> Warum benutzt du einen Wert, der in der referenzierten Tabelle
> *garantiert* nicht vorkommen kann (wegen des AUTO_INCREMENTs)?
> phpMyAdmin?
>
>> `von` datetime NOT NULL default '0000-00-00 00:00:00',
>> `bis` datetime NOT NULL default '0000-00-00 00:00:00',
>
> Warum setzt du ein ungültiges Datum als Default? phpMyAdmin?

Warum bringst Du ein Wekzeug hier ins Spiel, von dem nicht die Rede war
und das hier nicht ontopic ist? Pawlow? (SCNR)


create temporary table ttt (a int not null, b datetime not null);
show create table ttt\G
*************************** 1. row ***************************
Table: ttt
Create Table: CREATE TEMPORARY TABLE `ttt` (
`a` int(11) NOT NULL default '0',
`b` datetime NOT NULL default '0000-00-00 00:00:00'
) ENGINE=MyISAM DEFAULT CHARSET=utf8
1 row in set (0,00 sec)

Das macht MySQL von sich aus. Ganz ohne phpMyAdmin.


Das einzige, was man diesem Notbehelf an dieser Stelle vorwerfen kann,
ist vielleicht, daß es Felder standardmäßig mit NOT NULL anlegt.


Thomas

Re: Wie mehrere Termine n : 1 Kurse richtig joinen?

am 10.07.2006 11:08:05 von Kai Ruhnau

Thomas Rachel wrote:
> Kai Ruhnau wrote:
>
>>> ich habe eine Tabelle mit Terminen:
>>>
>>> CREATE TABLE `kd55`.`termine` (
>>> `id` int(10) unsigned NOT NULL auto_increment,
>>> `kurse_id` int(10) unsigned NOT NULL default '0',
>> Warum benutzt du einen String als Default für einen INT? phpMyAdmin?
>> Warum benutzt du einen Wert, der in der referenzierten Tabelle
>> *garantiert* nicht vorkommen kann (wegen des AUTO_INCREMENTs)?
>> phpMyAdmin?
>>
>>> `von` datetime NOT NULL default '0000-00-00 00:00:00',
>>> `bis` datetime NOT NULL default '0000-00-00 00:00:00',
>> Warum setzt du ein ungültiges Datum als Default? phpMyAdmin?
>
> Warum bringst Du ein Wekzeug hier ins Spiel, von dem nicht die Rede war
> und das hier nicht ontopic ist? Pawlow? (SCNR)

Jein. Ich hab gerade nochmal in mein Schema geschaut. Aufgrund von alten
Arbeitsabläufen (mit diesem "Tool") ging ich davon aus, dass das
phpMyAdmin verhunzt hat. Ich hab mir das gerade nochmal genauer
angeschaut und:

> create temporary table ttt (a int not null, b datetime not null);
> show create table ttt\G
> *************************** 1. row ***************************
> Table: ttt
> Create Table: CREATE TEMPORARY TABLE `ttt` (
> `a` int(11) NOT NULL default '0',
> `b` datetime NOT NULL default '0000-00-00 00:00:00'
> ) ENGINE=MyISAM DEFAULT CHARSET=utf8
> 1 row in set (0,00 sec)
>
> Das macht MySQL von sich aus. Ganz ohne phpMyAdmin.

mysql> create temporary table ttt (a int not null, b datetime not null)
ENGINE=MyISAM;

mysql> SHOW create TABLE ttt\G;
*************************** 1. row ***************************
Table: ttt
Create Table: CREATE TEMPORARY TABLE `ttt` (
`a` int(11) NOT NULL,
`b` datetime NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8

mysql> SELECT VERSION();
+------------+
| VERSION() |
+------------+
| 5.0.19-log |
+------------+
1 row in set (0.00 sec)

Hmm...

Aber alle Tabellen aus der Prä-5.0 Zeit haben diesen stillen Default
noch. Sehr ärgerlich. Da muss ich wohl demnächst mal mit dem großen
Schemaaufräumer drüber.

> Das einzige, was man diesem Notbehelf an dieser Stelle vorwerfen kann,
> ist vielleicht, daß es Felder standardmäßig mit NOT NULL anlegt.

.... und damit in den älteren Versionen diesen Müll-Defaultwert erzeugt.

Grüße
Kai

Re: Wie mehrere Termine n : 1 Kurse richtig joinen?

am 10.07.2006 11:46:02 von Thomas Rachel

Kai Ruhnau wrote:

> [5.0.19-Tabellen zeigen Defaultwerte nicht an]
> Hmm...
>
> Aber alle Tabellen aus der Prä-5.0 Zeit haben diesen stillen Default
> noch. Sehr ärgerlich. Da muss ich wohl demnächst mal mit dem großen
> Schemaaufräumer drüber.

Interessant - offenbar werden diese Defaultwerte bei 5.0 nicht mehr
unbedingt in der Spaltendefinition gespeichert, sondern eben
datenbankintern gehandhabt?

Aber, wenn ich das richtig in Erinnerung habe: Der Wert '0000-00-00
00:00:00' ist auch der Wert, der eingefügt wird, wenn ich einen
unzulässigen Wert einfügen will. So falsch ist der also als Default einer
"NOT NULL"-Spalte dann ja nicht (wenn auch unschön).


> Aber alle Tabellen aus der Prä-5.0 Zeit haben diesen stillen Default
> noch. Sehr ärgerlich. Da muss ich wohl demnächst mal mit dem großen
> Schemaaufräumer drüber.

Naja, optisch nicht schön - aber ich vermute, das Verhalten wird genauso
bleiben, denk ich mal...


>> Das einzige, was man diesem Notbehelf an dieser Stelle vorwerfen kann,
>> ist vielleicht, daß es Felder standardmäßig mit NOT NULL anlegt.
>
> ... und damit in den älteren Versionen diesen Müll-Defaultwert erzeugt.

eigentlich ja dann: "...erzeugen läßt".

Thomas

Re: Wie mehrere Termine n : 1 Kurse richtig joinen?

am 10.07.2006 11:50:04 von Harald Fuchs

In article ,
Thomas Rachel writes:

> create temporary table ttt (a int not null, b datetime not null);
> show create table ttt\G
> *************************** 1. row ***************************
> Table: ttt
> Create Table: CREATE TEMPORARY TABLE `ttt` (
> `a` int(11) NOT NULL default '0',
> `b` datetime NOT NULL default '0000-00-00 00:00:00'
> ) ENGINE=MyISAM DEFAULT CHARSET=utf8
> 1 row in set (0,00 sec)

> Das macht MySQL von sich aus.

Aber nur, wenn Du nicht das sehr empfehlenswerte sql_mode=TRADITIONAL
verwendest.

Re: Wie mehrere Termine n : 1 Kurse richtig joinen?

am 10.07.2006 11:53:29 von Thomas Rachel

Saša Ebach wrote:

>> Warum benutzt du einen Wert, der in der referenzierten Tabelle
>> *garantiert* nicht vorkommen kann (wegen des AUTO_INCREMENTs)?
>> phpMyAdmin?
>
> kurse_id sollte keinen default haben. Kann es sein, dass MySQL
> Administrator den dahingepfuscht hat?

*Irgendeinen* Default muß es ja haben - der hier (vermutlich aus früüheren
Zeiten übriggeblieben) auch angezeigt wird.

Aber da Du ja InnoDB verwendest, womit ich mich nicht sonderlich auskenne:
dieses Default-Problem sollte sich aus der Welt schaffen lassen, wenn Du
ein entsprechendes Constraint anlegst.


> Referenzielle Integrität halte ich über Transaktionen und die Anwendung
> aufrecht. Ich halte nicht sehr viel davon die Datenbank zu viel
> Verantwortung übernehmen zu lassen.

Naja, dafür gibts diese Fähigkeiten ja.

Es schadet ja auch nicht, *beides* zu verwenden (außer daß es etwas
Rechenzeit kostet)...


Thomas

Re: Wie mehrere Termine n : 1 Kurse richtig joinen?

am 10.07.2006 16:48:47 von Kai Ruhnau

Thomas Rachel wrote:
> Kai Ruhnau wrote:
>
>> [5.0.19-Tabellen zeigen Defaultwerte nicht an]
>> Hmm...
>>
>> Aber alle Tabellen aus der Prä-5.0 Zeit haben diesen stillen Default
>> noch. Sehr ärgerlich. Da muss ich wohl demnächst mal mit dem großen
>> Schemaaufräumer drüber.
>
> Interessant - offenbar werden diese Defaultwerte bei 5.0 nicht mehr
> unbedingt in der Spaltendefinition gespeichert, sondern eben
> datenbankintern gehandhabt?
>
> Aber, wenn ich das richtig in Erinnerung habe: Der Wert '0000-00-00
> 00:00:00' ist auch der Wert, der eingefügt wird, wenn ich einen
> unzulässigen Wert einfügen will. So falsch ist der also als Default einer
> "NOT NULL"-Spalte dann ja nicht (wenn auch unschön).

Doch, er ist falsch. Wenn ich keinen Default-Wert angebe, dann möchte
ich auch keinen haben. Erst recht möchte ich keinen ungültigen Wert (Das
Jahr 0, den Monat 0 oder den Tag 0 gab es nie und wird es auch nie
geben). Andreas hat schon recht, wenn er dieses Verhalten von MySQL
bemängelt.

>> Aber alle Tabellen aus der Prä-5.0 Zeit haben diesen stillen Default
>> noch. Sehr ärgerlich. Da muss ich wohl demnächst mal mit dem großen
>> Schemaaufräumer drüber.
>
> Naja, optisch nicht schön - aber ich vermute, das Verhalten wird genauso
> bleiben, denk ich mal...

Wie Harald schrieb gibt es ein paar empfehlenswerte Einstellungen für
den SQL_MODE:

mysql> INSERT INTO ttt SET a=0;
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> SHOW WARNINGS;
+---------+------+----------------------------------------+
| Level | Code | Message |
+---------+------+----------------------------------------+
| Warning | 1364 | Field 'b' doesn't have a default value |
+---------+------+----------------------------------------+
1 row in set (0.00 sec)

mysql> SET SESSION sql_mode='ANSI,TRADITIONAL';
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO ttt SET a=0;
ERROR 1364 (HY000): Field 'b' doesn't have a default value

mysql> INSERT INTO ttt SET a=0, b='0000-00-00';
ERROR 1292 (22007): Incorrect datetime value: '0000-00-00' for column
'b' at row 1


Aber, und das ist der richtig ärgerliche Teil:

Eigentlich kann man mit SQL_MODE='Traditional' keine ungültigen Daten
einfügen. Man kann auch nicht einem CREATE TABLE den DEFAULT auf ein
ungültiges Datum setzen. Wenn allerdings die Tabelle mit dem ungültigen
Default-Eintrag angelegt worden ist (prä-5.0 oder SQL_MODE ohne
traditional), dann funktioniert das obige INSERT ohne Angabe von b
trotzdem und fügt den ungültigen Wert '0000-00-00...' in die Spalte `b`
ein - vorbei an allen Schutzmaßnahmen.

Ich hab mal http://bugs.mysql.com/20943 erstellt.

Grüße
Kai

Re: Wie mehrere Termine n : 1 Kurse richtig joinen?

am 10.07.2006 17:35:50 von Thomas Rachel

Kai Ruhnau wrote:

>> Aber, wenn ich das richtig in Erinnerung habe: Der Wert '0000-00-00
>> 00:00:00' ist auch der Wert, der eingefügt wird, wenn ich einen
>> unzulässigen Wert einfügen will. So falsch ist der also als Default einer
>> "NOT NULL"-Spalte dann ja nicht (wenn auch unschön).
>
> Doch, er ist falsch. Wenn ich keinen Default-Wert angebe, dann möchte
> ich auch keinen haben.

Ok, mir war nicht bewußt, daß das unter 5.0 anders ist: früher gab es AFAIR
keine Spalten ohne Defaultwert; das Verhalten, daß Du weiter unten mit

> mysql> INSERT INTO ttt SET a=0;
> ERROR 1364 (HY000): Field 'b' doesn't have a default value

erzielst, ist unter dieser Prämisse natürlich korrekt.

Allerdings finde ich es korrekt, daß Deine Tabellen, die Du von 4.x
übernommen hast, auch weiterhin diesen Default tragen - damit wird ja das
bisherige Verhalten beibehalten.

> Wenn allerdings die Tabelle mit dem ungültigen
> Default-Eintrag angelegt worden ist (prä-5.0 oder SQL_MODE ohne
> traditional), dann funktioniert das obige INSERT ohne Angabe von b
> trotzdem und fügt den ungültigen Wert '0000-00-00...' in die Spalte `b`
> ein - vorbei an allen Schutzmaßnahmen.

Das ist in der Tat unschön - allerdings könnte man damit argumentieren: Wer
die Tabelle angelegt hat, bestimmt auch, was hineingehört - vielleicht hat
dieser an sich ungültige Wert ja eine Spezialbedeutung und ist somit trotz
serverseitig gesetztem SQL_MODE=traditional als korrekt anzusehen. YMMV.


Thomas