<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Groschengedanken zu Software &#187; mysql</title>
	<atom:link href="http://aysx.de/eingroschen/?feed=rss2&#038;tag=mysql" rel="self" type="application/rss+xml" />
	<link>http://aysx.de/eingroschen</link>
	<description>... und vielleicht auch dem ganzen Rest</description>
	<lastBuildDate>Tue, 18 Jun 2019 17:59:37 +0000</lastBuildDate>
	<language>de-DE</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.2.38</generator>
	<item>
		<title>Weihnachtsgeschäft</title>
		<link>http://aysx.de/eingroschen/?p=186</link>
		<comments>http://aysx.de/eingroschen/?p=186#comments</comments>
		<pubDate>Tue, 19 Nov 2013 20:28:58 +0000</pubDate>
		<dc:creator><![CDATA[matthias]]></dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[crm]]></category>
		<category><![CDATA[Kundenbetreuung]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[Wirtschaftsinformatik]]></category>

		<guid isPermaLink="false">http://aysx.de/eingroschen/?p=186</guid>
		<description><![CDATA[Es ist November, das Weihnachtsgeschäft soll&#8217;s &#8216;rausreissen. Also schicken wir denjenigen Kunden eine Ansichtskarte an die letzte Lieferadresse, die seit zwei Jahren nichts gekauft haben, aber davor wenigstens dreimal etwas geordert haben. Jetzt Du, Programmierer &#8230; Hier ist ein Ausschnitt &#8230; <a href="http://aysx.de/eingroschen/?p=186">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Es ist November, das Weihnachtsgeschäft soll&#8217;s &#8216;rausreissen. Also schicken wir denjenigen Kunden eine Ansichtskarte an die letzte Lieferadresse, die seit zwei Jahren nichts gekauft haben, aber davor wenigstens dreimal etwas geordert haben. Jetzt Du, Programmierer &#8230;</p>
<p>Hier ist ein Ausschnitt der (My)Sql-Tabellen-Struktur, gefüllt mit Fantasie-Daten. Ich habe es für MySQL entwickelt, es sollte mit keinen oder wenigen Anpassungen auf andere RDBMS übertragbar sein.</p><pre class="crayon-plain-tag">CREATE TABLE adresse
(
   id int PRIMARY KEY NOT NULL,
   vorname varchar(45),
   name varchar(45),
   strasse varchar(80),
   plz varchar(10),
   ort varchar(20)
);

insert into adresse (id,vorname,name,strasse,plz,ort) values (1,'Peter','Mustermann','Musterstr.42','12345','Musterhausen');
insert into adresse (id,vorname,name,strasse,plz,ort) values (2,'Paul','Mustermann','Musterstr.43','12345','Musterhausen');
insert into adresse (id,vorname,name,strasse,plz,ort) values (3,'Erika','Musterfrau','Musterstr.44','12345','Musterhausen');
insert into adresse (id,vorname,name,strasse,plz,ort) values (4,'Erna','Normalverbraucher','Musterstr.45','12345','Musterhausen');
insert into adresse (id,vorname,name,strasse,plz,ort) values (5,'Erna','Normalverbraucher','Ottostr.45','12345','Musterhausen');

CREATE TABLE bestellung
(
   id int PRIMARY KEY NOT NULL,
   rechnungsadresse int DEFAULT 0 NOT NULL,
   lieferadresse int DEFAULT 0 NOT NULL,
   id_person int DEFAULT 0 NOT NULL,
   datum timestamp NOT NULL
);

insert into bestellung (id,rechnungsadresse,lieferadresse,id_person,datum) values (1,1,1,1,'2010.12.01');
insert into bestellung (id,rechnungsadresse,lieferadresse,id_person,datum) values (2,1,1,1,'2011.01.01');
insert into bestellung (id,rechnungsadresse,lieferadresse,id_person,datum) values (3,1,1,1,'2011.02.01');
insert into bestellung (id,rechnungsadresse,lieferadresse,id_person,datum) values (4,1,1,1,'2011.12.01');
insert into bestellung (id,rechnungsadresse,lieferadresse,id_person,datum) values (5,1,1,1,'2012.01.01');
insert into bestellung (id,rechnungsadresse,lieferadresse,id_person,datum) values (6,1,1,1,'2012.12.01');
insert into bestellung (id,rechnungsadresse,lieferadresse,id_person,datum) values (7,2,2,2,'2010.12.02');
insert into bestellung (id,rechnungsadresse,lieferadresse,id_person,datum) values (8,2,2,2,'2011.02.01');
insert into bestellung (id,rechnungsadresse,lieferadresse,id_person,datum) values (9,3,3,3,'2011.02.03');
insert into bestellung (id,rechnungsadresse,lieferadresse,id_person,datum) values (10,3,3,3,'2011.12.03');
insert into bestellung (id,rechnungsadresse,lieferadresse,id_person,datum) values (11,3,3,3,'2012.03.03');
insert into bestellung (id,rechnungsadresse,lieferadresse,id_person,datum) values (12,3,3,3,'2012.12.03');
insert into bestellung (id,rechnungsadresse,lieferadresse,id_person,datum) values (13,4,4,4,'2011.05.04');
insert into bestellung (id,rechnungsadresse,lieferadresse,id_person,datum) values (14,4,4,4,'2011.07.04');
insert into bestellung (id,rechnungsadresse,lieferadresse,id_person,datum) values (15,5,4,4,'2011.09.04');</pre><p>Zuerst finde heraus, wer wieoft bestellt hat und wann die letzte Bestellung stattfand &#8211; unter Bachtung der oben gegebenen Einschränkungen:</p><pre class="crayon-plain-tag">-- INTERVAL 22 MONTH
-- weil es erst November ist und wir den Januar auch &quot;mitnehmen&quot; m&ouml;chten.

SELECT id_person, max(datum) as letzteBestellung, count(*) as anzahlBestellungen
FROM (
	SELECT id_person, datum
	FROM bestellung
) t1
group by id_person
having count(*) &amp;gt;= 3 -- wenigstens 3 Bestellungen 
and max(datum) &amp;lt; DATE_SUB(now(), INTERVAL 22 MONTH) -- und seit 22 Monaten ohne Umsatz</pre><p>Aufgrund dieser Daten suche ich die Rechnungsadresse &#8211; mit einem self-join:</p><pre class="crayon-plain-tag">SELECT distinct taba.id_person, tabb.letzteBestellung, tabb.anzahlBestellungen, taba.rechnungsadresse
FROM bestellung taba inner join
(
	SELECT id_person, max(datum) as letzteBestellung, count(*) as anzahlBestellungen
	FROM (
		SELECT id_person, datum
		FROM bestellung
	) t1
	group by id_person
	having count(*) &amp;gt;= 3
	and max(datum) &amp;lt; DATE_SUB(now(), INTERVAL 22 MONTH)
) tabb
on (taba.id_person = tabb.id_person
and tabb.letzteBestellung = taba.datum)</pre><p>Und dann brauche ich das nur noch mit den Adressen zu verbinden und habe das Ergebnis:</p><pre class="crayon-plain-tag">SELECT *
FROM (
	SELECT distinct taba.id_person, tabb.letzteBestellung, tabb.anzahlBestellungen, taba.rechnungsadresse
	FROM bestellung taba inner join
	(
		SELECT id_person, max(datum) as letzteBestellung, count(*) as anzahlBestellungen
		FROM (
			SELECT id_person, datum
			FROM bestellung
		) t1
		group by id_person
		having count(*) &amp;gt;= 3
		and max(datum) &amp;lt; DATE_SUB(now(), INTERVAL 22 MONTH)
	) tabb
	on (taba.id_person = tabb.id_person
	and tabb.letzteBestellung = taba.datum)
) ago inner join adresse
on ago.rechnungsadresse = adresse.id</pre><p>Die Bestelldaten sind auch für Menschen überschaubar. Peter bekommt keine Karte, weil er ein treuer Kunde ist und wir hoffen, dass er in diesem Jahr auch so wieder etwas bestellt. Paul bekommt keine Karte, weil er &#8211; nach unseren Masstäben &#8211; kein Interesse hat. Erika ergeht es wie Peter. Aber eine Karte in Erna zu investieren lohnt bestimmt!</p>
<p>Aufräumen nicht vergessen, weil das nur ein Bespiel ist.</p><pre class="crayon-plain-tag">drop table bestellung;
drop table adresse;</pre><p>Und das SQL ist so, dass wir es im kommenden Jahr wieder verwenden können. Der Serienbrief-Druck kann beginnen.</p>
<p>Über den Sinn und Unsinn einer solchen Weihnachtskarten-Aktion kann man trefflich streiten. Erfolgskontrolle wird die Marketing-Abteilung freuen: Wer von den angeschriebenen hat wieder etwas bei uns gekauft? Und warum? War die Karte der Auslöser oder die Trennung vom Partner oder &#8230; was?</p>
]]></content:encoded>
			<wfw:commentRss>http://aysx.de/eingroschen/?feed=rss2&#038;p=186</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>join vs subselect</title>
		<link>http://aysx.de/eingroschen/?p=175</link>
		<comments>http://aysx.de/eingroschen/?p=175#comments</comments>
		<pubDate>Tue, 19 Nov 2013 19:12:58 +0000</pubDate>
		<dc:creator><![CDATA[matthias]]></dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[forschung]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://aysx.de/eingroschen/?p=175</guid>
		<description><![CDATA[Vor einigen Jahren habe ich für den Mssql-Server herausgefunden, dass Abfragen mit &#8220;join&#8221; mehr als 100 mal schneller sein können als die gleich Abfrage in Form eines Subselects. Stimmt das auch heute für MySQL? Folgendes zeigt, dass es nicht zwingend &#8230; <a href="http://aysx.de/eingroschen/?p=175">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Vor einigen Jahren habe ich für den Mssql-Server herausgefunden, dass Abfragen mit &#8220;join&#8221; mehr als 100 mal schneller sein können als die gleich Abfrage in Form eines Subselects. Stimmt das auch heute für MySQL? Folgendes zeigt, dass es nicht zwingend so ist.</p>
<p>Frage: Welche Postleitzahlen gibt es sowohl in Deutschland als auch in den USA?</p>
<p>Stationen auf dem Weg zur Antwort:</p>
<li> Quelle von PLZ-dumps<br />
http://www.tutorials.de/relationale-datenbanksysteme/229059-postleitzahlen-mysql-dump.html<br />
=> Einspielen in die Tabelle &#8216;orte&#8217;.</p>
<li> Quelle US Zip-Codes<br />
http://federalgovernmentzipcodes.us/free-zipcode-database.csv<br />
aufbereiten mit<br />
cut -d &#8220;,&#8221; -f2,4 free-zipcode-database.csv &gt; free-zipcode-database-zip-city-only.csv<br />
Ergänzung für einen brauchbaren MySQL-Dump überlasse ich dem geneigten Publikum.<br />
=> Einspielen in die Tabelle &#8216;orteus&#8217;.</p>
<li> SQL-Befehle übersichtlich strukturiert. Sie werden unten als 1-Zeiler benutzt:
<p></p><pre class="crayon-plain-tag">-- join
--
SELECT count(*)
FROM (
&nbsp;&nbsp; &nbsp;SELECT distinct orte.PLZ FROM 
&nbsp;&nbsp; &nbsp;orte, orteus
&nbsp;&nbsp; &nbsp;where orte.PLZ = orteus.PLZ
) t1;

-- subselect
--
SELECT count(*)
FROM (
&nbsp;&nbsp; &nbsp;SELECT distinct orte.PLZ
&nbsp;&nbsp; &nbsp;FROM orte
&nbsp;&nbsp; &nbsp;where orte.PLZ in (
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;select orteus.PLZ FROM orteus
&nbsp;&nbsp; &nbsp;)
) t2;</pre><p></p>
<p>Copy&#038;Paste aus dem mysql-Client:</p>
<p></p><pre class="crayon-plain-tag">mysql&amp;gt; select count(*) from orte;
 +----------+
 | count(*) |
 +----------+
 |&nbsp;&nbsp;&nbsp; 44188 |
 +----------+
 1 row in set (0.00 sec)

mysql&amp;gt; select count(*) from orteus;
+----------+
| count(*) |
+----------+
|&nbsp;&nbsp;&nbsp; 81831 |
+----------+
1 row in set (0.00 sec)

mysql&amp;gt; SELECT count(*) FROM (SELECT distinct orte.PLZ FROM orte, orteus where orte.PLZ = orteus.PLZ) t1;
+----------+
| count(*) |
+----------+
|&nbsp;&nbsp;&nbsp; 13365 |
+----------+
1 row in set (0.16 sec)

mysql&amp;gt; SELECT count(*) FROM (SELECT distinct orte.PLZ FROM orte where orte.PLZ in (select orteus.PLZ FROM orteus)) t2;
+----------+
| count(*) |
+----------+
|&nbsp;&nbsp;&nbsp; 13365 |
+----------+
1 row in set (0.18 sec)</pre><p></p>
<p>Ergebnis: Für ca. 44000&#215;81000 ist fast kein Unterschied auszumachen.<br />
Ich bin angenehm überrascht. Einschränkung der Gültigkeit der Erkenntnis: Die Datenmenge im obigen Beispiel ist nicht gross. Damals bei Mssql ging es um ungefähr 12000&#215;625000, also Faktor 0,5 aber immerhin diesselbe Grössenordnung.</p>
]]></content:encoded>
			<wfw:commentRss>http://aysx.de/eingroschen/?feed=rss2&#038;p=175</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Beispiel Warenkorbanalyse in sql</title>
		<link>http://aysx.de/eingroschen/?p=83</link>
		<comments>http://aysx.de/eingroschen/?p=83#comments</comments>
		<pubDate>Sun, 13 Oct 2013 18:40:33 +0000</pubDate>
		<dc:creator><![CDATA[matthias]]></dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://aysx.de/eingroschen/?p=83</guid>
		<description><![CDATA[[crayon-69f90d1c4ca4a584496238/]]]></description>
				<content:encoded><![CDATA[<p></p><pre class="crayon-plain-tag">use test

/*
	Warenkorb-Analyse
	=================
	
	Bei youtube fand ich ein Science-Slam-Video zu Wirtschafts-Informatik,
	bei dem das Stichwort &quot;Warenkorbanalyse&quot; fiel. Interessante Sache 
	das, also habe ich das Beispiel aus dem Video in MySQL nachgebaut.
*/

create table einkauf
(
	e_id int,
	prod_id int
);

create table produkt
(
	prod_id int,
	name varchar (255)
);

insert into produkt ( prod_id, name ) values ( 1 , 'Cola');
insert into produkt ( prod_id, name ) values ( 2 , 'Milch');
insert into produkt ( prod_id, name ) values ( 3 , 'Bier');
insert into produkt ( prod_id, name ) values ( 4 , 'Pizza');
insert into produkt ( prod_id, name ) values ( 5 , 'Pampers');

insert into einkauf ( e_id, prod_id ) values ( 1, 1 );
insert into einkauf ( e_id, prod_id ) values ( 1, 2 );
insert into einkauf ( e_id, prod_id ) values ( 1, 4 );
insert into einkauf ( e_id, prod_id ) values ( 2, 2 );
insert into einkauf ( e_id, prod_id ) values ( 2, 5 );
insert into einkauf ( e_id, prod_id ) values ( 3, 1 );
insert into einkauf ( e_id, prod_id ) values ( 3, 4 );
insert into einkauf ( e_id, prod_id ) values ( 4, 2 );
insert into einkauf ( e_id, prod_id ) values ( 4, 3 );
insert into einkauf ( e_id, prod_id ) values ( 5, 1 );
insert into einkauf ( e_id, prod_id ) values ( 5, 3 );

SELECT * FROM produkt;
SELECT * FROM einkauf;

/*
	Alle Produkt-Paare aus den Eink&auml;ufen herausfinden, d.h.
	f&uuml;r jeden Einkauf jedes Produkt mit allen anderen
	Produkten dieses Einkaufs kombinieren.
	NB: Wenn ein Produkt innerhalb eines Einkaufs mehrfach
	vorkommt, dann muss das vorher gruppiert werden. Ich gehe
	hier oBdA davon aus, dass jedes Produkt nur einmal in jedem
	Einkauf vorkommt.
*/

SELECT ek1.e_id, ek1.prod_id, ek2.prod_id
FROM einkauf ek1, einkauf ek2
where ek1.e_id = ek2.e_id;

/*
	An dieser Stelle spielt die Einkaufsnummer keine Rolle.
	Hauptsache, ich kenne alle Paarungen.
	Das sind die Paarungen, die vorkommen.
	Was ist mit denen, die nicht vorkommen?
*/

SELECT ek1.prod_id, ek2.prod_id
FROM einkauf ek1, einkauf ek2
where ek1.e_id = ek2.e_id;

/*
	So gruppieren, dass ich sehe, welches Paar wie oft
	vorkommt.
	Die Zeilen, bei denen ek1.prod_id = ek2.prod_id ist,
	geben an, wie oft das Produkt mit der ek1.prod_id
	insgesamt gekauft wurde. 
*/

SELECT ekl.prod_id as prodA, ekr.prod_id as prodB, count(ekl.prod_id) as anzahl
FROM einkauf ekl, einkauf ekr
where ekl.e_id = ekr.e_id
group by prodA, prodB;

/*
	Welche Kombinationen fehlen f&uuml;r das jeweilige Produkt?
	Nun, vergleiche die obige Tabelle mit dem kartesischen Produkt
	der Waren.
*/

SELECT * 
FROM (
	SELECT ekl.prod_id as prodA, ekr.prod_id as prodB, count(ekl.prod_id) as anzahl
	FROM einkauf ekl, einkauf ekr
	where ekl.e_id = ekr.e_id
	group by prodA, prodB
) tupels 
right outer join 
(
	select prl.prod_id as prodR, prr.prod_id as prodL
	from produkt prl, produkt prr
) alleWarenTupel
on tupels.prodA = alleWarenTupel.prodR
and tupels.prodB = alleWarenTupel.prodL;

/*
	Von obiger Tabelle zeige ich prodA und prodB nicht an,
	denn prodR und prodL sind bedeutungsgleich. Wichtig ist,
	dass ich f&uuml;r die jeweilige Paarung die Anzahl kenne.
*/

SELECT alleWarenTupel.prodL, alleWarenTupel.prodR, tupels.anzahl
FROM (
	SELECT ekl.prod_id as prodA, ekr.prod_id as prodB, count(ekl.prod_id) as anzahl
	FROM einkauf ekl, einkauf ekr
	where ekl.e_id = ekr.e_id
	group by prodA, prodB
) tupels 
right outer join 
(
	select prl.prod_id as prodR, prr.prod_id as prodL
	from produkt prl, produkt prr
) alleWarenTupel
on tupels.prodA = alleWarenTupel.prodR
and tupels.prodB = alleWarenTupel.prodL;

/*
	Wie bekomme ich eine h&uuml;bsche Tabelle?
	Ich h&auml;tte gerne die Spalte &quot;anzahl&quot; in F&uuml;nfer-Pakete aufgeteilt, so
	dass die ersten f&uuml;nf Werte hintereinander stehen, in der zweiten
	Zeile die zweiten f&uuml;nf Werte usw.
	F&uuml;r MSSQL scheint es unkompliziert, siehe
	http://www.brighthub.com/internet/web-development/articles/91895.aspx
	F&uuml;r MySQL ist es umst&auml;ndlich(er)
	http://www.onlamp.com/pub/a/onlamp/2003/12/04/crosstabs.html

	Schlie&szlig;lich ein Dank an
	http://en.wikibooks.org/wiki/MySQL/Pivot_table

	Wermutstropfen: Die Spaltennamen sind &quot;hardcodiert&quot;. Bei gro&szlig;em
	Produktumfang wird das eine Qual :/, also doch besser in eine 
	Tabellenkalkulation bringen.
*/

select prodL, ProdName,
sum(anzahl*(1-abs(sign(prodR-1)))) as 'Cola',
sum(anzahl*(1-abs(sign(prodR-2)))) as 'Milch',
sum(anzahl*(1-abs(sign(prodR-3)))) as 'Bier',
sum(anzahl*(1-abs(sign(prodR-4)))) as 'Pizza',
sum(anzahl*(1-abs(sign(prodR-5)))) as 'Pampers'
from (
	SELECT alleWarenTupel.prodL, alleWarenTupel.ProdName, alleWarenTupel.prodR, tupels.anzahl
		FROM (
		SELECT ekl.prod_id as prodA, ekr.prod_id as prodB, count(ekl.prod_id) as anzahl
		FROM einkauf ekl, einkauf ekr
		where ekl.e_id = ekr.e_id
		group by prodA, prodB
	) tupels 
	right outer join 
	(
		select prl.prod_id as prodR, prr.prod_id as prodL, prr.name as ProdName
		from produkt prl, produkt prr
	) alleWarenTupel
	on tupels.prodA = alleWarenTupel.prodR
	and tupels.prodB = alleWarenTupel.prodL
) pivot
group by prodL, ProdName;

select ProdName, Cola, Milch, Bier, Pizza, Pampers
from 
(
	select prodL, ProdName,
	sum(anzahl*(1-abs(sign(prodR-1)))) as 'Cola',
	sum(anzahl*(1-abs(sign(prodR-2)))) as 'Milch',
	sum(anzahl*(1-abs(sign(prodR-3)))) as 'Bier',
	sum(anzahl*(1-abs(sign(prodR-4)))) as 'Pizza',
	sum(anzahl*(1-abs(sign(prodR-5)))) as 'Pampers'
	from (
		SELECT alleWarenTupel.prodL, alleWarenTupel.ProdName, alleWarenTupel.prodR, tupels.anzahl
			FROM (
			SELECT ekl.prod_id as prodA, ekr.prod_id as prodB, count(ekl.prod_id) as anzahl
			FROM einkauf ekl, einkauf ekr
			where ekl.e_id = ekr.e_id
			group by prodA, prodB
		) tupels 
		right outer join 
		(
			select prl.prod_id as prodR, prr.prod_id as prodL, prr.name as ProdName
			from produkt prl, produkt prr
		) alleWarenTupel
		on tupels.prodA = alleWarenTupel.prodR
		and tupels.prodB = alleWarenTupel.prodL
	) pivot
	group by prodL, ProdName
) nice;

-- Aufr&auml;umen;
--
drop table einkauf;
drop table produkt;

-- Ende.</pre><p></p>
]]></content:encoded>
			<wfw:commentRss>http://aysx.de/eingroschen/?feed=rss2&#038;p=83</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rang in sql</title>
		<link>http://aysx.de/eingroschen/?p=53</link>
		<comments>http://aysx.de/eingroschen/?p=53#comments</comments>
		<pubDate>Sun, 06 Oct 2013 18:44:53 +0000</pubDate>
		<dc:creator><![CDATA[matthias]]></dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[rang]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://aysx.de/eingroschen/?p=53</guid>
		<description><![CDATA[[crayon-69f90d1c4cfaf767965991/] Natürlich ist das obige Beispiel so in der Praxis nicht vorgekommen. Das Beispiel zeigt eine nützliche Struktur. Im Laufe der Zeit kam immer wieder die Anforderung der Durchnummerierung. Man braucht dazu keinen PK-Constraint, aber wenigstens irgendein Tupel, das unique &#8230; <a href="http://aysx.de/eingroschen/?p=53">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p></p><pre class="crayon-plain-tag">/*
	Nummeriere die Datens&auml;tze
	*************************

	Gegeben sei eine Tabelle aysx mit einem Primary Key. 
        Die Werte f&uuml;r den PK m&uuml;ssen nicht fortlaufend sein. 

        Aufgabe: Nummeriere die Datens&auml;tze 
	vom kleinsten bis zum gr&ouml;&szlig;sten PK-Wert.

	Das folgende MySQL-Script zeigt exemplarisch, wie 
        das machbar ist. Bedenke, dass die Bestimmung des 
        Rangs (gidf) nicht auf eine &quot;echte&quot; Tabelle beschr&auml;nkt 
        ist, sondern auch mit einem View und dem Ergebnis
	einer Abfrage durchgef&uuml;hrt werden kann.

	Beispieltext: aysx Matthias Kopp 2013
*/

create table aysx ( 
	id int PRIMARY KEY, 
	remark varchar ( 64 ));

/*
	Tabelle mit Beispieldaten f&uuml;llen.
*/

insert into aysx ( id, remark ) values ( 1,	'Eins' );
insert into aysx ( id, remark ) values ( 512,	'FiveOneTwo' );
insert into aysx ( id, remark ) values ( 21,	'Antv' );
insert into aysx ( id, remark ) values ( 42,	'Antwort' );
insert into aysx ( id, remark ) values ( 23,	'whatever' );

/*
	Wesentlich ist der self-join. Der PK-Constraint garantiert,
	dass jede aysx.id nur einmal vorkommt. Eine id ist immer
	gleich ihrer selbst und alle anderen sind entweder gr&ouml;&szlig;er
	oder kleiner. Die where-Bedingung sucht diejenigen Datens&auml;tze
	zusammen, die kleiner-gleich einer id sind - und das f&uuml;r
	alle ids. Schlie&szlig;lich wird f&uuml;r jede id eine Gruppe gebildet
	und die Anzahl der Elemente in der Gruppe ist eben der Rang.
*/

select count(*) as rang, t2.id
from aysx t1, aysx t2
where t1.id &amp;lt;= t2.id
group by t2.id;

/*
	Ohne Gruppierung und Z&auml;hlen - die &quot;expandierte&quot; Form.
	Hier kann man nachvollziehen, welche Elemente vorhanden sind.
	Z&auml;hle und gruppiere selbst!
*/

select t1.id, t2.id
from aysx t1, aysx t2
where t1.id &amp;lt;= t2.id
order by t2.id

/* Aur&auml;umen. */
drop table aysx;</pre><p>Natürlich ist das obige Beispiel so in der Praxis nicht vorgekommen. Das Beispiel zeigt eine nützliche Struktur. Im Laufe der Zeit kam immer wieder die Anforderung der Durchnummerierung. Man braucht dazu keinen PK-Constraint, aber wenigstens irgendein Tupel, das unique ist &#8211; und das findet sich. Jedenfalls konnte ich immer irgendwo eins auftreiben :)</p>
<p>Das Script oben habe ich mit Copy&amp;Paste aus <a title="SQuirrel SQL" href="http://www.squirrelsql.org/" target="_blank">SQuirreL SQL</a> übernommen, während ich mit einer<a title="MySQL" href="http://www.mysql.com/" target="_blank"> MySQL-Datenbank</a> verbunden war. Kann sein, dass andere RDBMS eine leicht abweichende Syntax haben. Aber im Prinzip sollte dieses Script auf gängigen SQL-Systemen lauffähig sein.</p>
]]></content:encoded>
			<wfw:commentRss>http://aysx.de/eingroschen/?feed=rss2&#038;p=53</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Daten konsistent halten</title>
		<link>http://aysx.de/eingroschen/?p=49</link>
		<comments>http://aysx.de/eingroschen/?p=49#comments</comments>
		<pubDate>Sun, 06 Oct 2013 16:06:55 +0000</pubDate>
		<dc:creator><![CDATA[matthias]]></dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[foreign key]]></category>
		<category><![CDATA[Konsistenz]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://aysx.de/eingroschen/?p=49</guid>
		<description><![CDATA[MySQL und andere RDBMS bieten die Möglichkeit, Foreign-Key-Constraints auszuschalten. Ich halte das für eine schlechte Idee. Ich kenne aus der Praxis ein Szenario, bei dem FK-Constraints ausgeschaltet wurden, um den Import von Daten zu ermöglichen. Die Daten lagen in unterschiedlichen &#8230; <a href="http://aysx.de/eingroschen/?p=49">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>MySQL und andere RDBMS bieten die Möglichkeit, Foreign-Key-Constraints auszuschalten. Ich halte das für eine schlechte Idee.</p>
<p>Ich kenne aus der Praxis ein Szenario, bei dem FK-Constraints ausgeschaltet wurden, um den Import von Daten zu ermöglichen. Die Daten lagen in unterschiedlichen Tabellen, verknüpft durch Foreign Keys. Man kriegt die einen Daten nicht &#8216;rein, wenn die anderen Daten nicht vorhanden sind. Bei einem System mit vielen Tabellen und Verbindungen wird das schnell zu einer &#8220;Plage&#8221;, weil man sich über die Reihenfolge bei Export und Import Gedanken machen muss. Vielleicht sind in dem exportierten System bestimmte Datenstrukturen gar nicht vorhanden, weil das einen anderen Versionsstand hat als das System, in das hinein importiert wird. Es ist verlockend einfach, die Contraints auszuschalten, die Daten reinzupumpen und zu hoffen, dass alles gut geht. RDBMS mit einer strikten Vorgehensweise, Beispiel Oracle, erlauben es nicht, Constraints einzuschalten, solange inkonsistente Daten vorliegen. Und dann hat man zwei Probleme, nämlich inkonsistente Daten und fehlende Contraints, die wiederum zu weiteren Inkonsistenzen führen können. Wohl dem Kunden, der einen Supportvertrag hat :(</p>
<p>Foreign-Key-Contraints auszuschalten heisst, schnell und dreckig zu arbeiten. Manchmal wird einen der Arbeitsdruck dazu verleiten &#8211; es muss ein Weg gefunden werden und zwar flott. Ich kenne das. Und ich weiss, dass das Aufräumen inkonsistenter Daten mächtig viel Zeit in Anspruch nehmen kann. Foreign-Key-Contraints-ausschalten als Notnagel: Ja. Als Dauerlösung im Code: Nein!</p>
]]></content:encoded>
			<wfw:commentRss>http://aysx.de/eingroschen/?feed=rss2&#038;p=49</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
