[MySQL] Query *gelöst*

ChristianK

Well-known member
ID: 85965
L
25 Mai 2006
92
1
Hi,

hänge im Moment an einem kleinem Query. Und zwar soll ein er unter "space" einen Eintrag hinzufügen wo per Zufall x und Y bestimmt wird. Jedoch darf X und Y nicht bereits unter dem Table "planeten" vergeben sein.

Wüsst ihr wie das gehen könnte?

Christian
 
Zuletzt bearbeitet:
PHP:
$insert = false;
srand();
while(!insert)
{
    $x = rand(0, 500);
    $y = rand(0, 500);
    $planeten = mysql_query('SELECT COUNT(*) FROM `planeten` WHERE `x` = '.$x.' AND `y` = '.$y);
    if(mysql_result($planeten, 0) == 0)
        $insert = mysql_query('INSERT INTO `space` (`x`, `y`) VALUES ('.$x.', '.$y.')');
}
Das läuft so lange rund, bis er einen Eintrag gefunden hat, der noch nicht in 'planeten' is ;)
 
Zuletzt bearbeitet:
@Claudi:
Indizes ausnutzen ! Wenn (x,y) ein UNIQUE-Index is, was es hierbei sein sollte (oder sollen mehr auf einer Stelle sein dürfen ?), dann kannst du mit
PHP:
do {
  mysql_query("INSERT IGNORE INTO ....");
} while(!mysql_affected_rows());
das einfacher machen, weil du pro Durchlauf eine Abfrage sparst.
 
@Claudi:
Indizes ausnutzen ! Wenn (x,y) ein UNIQUE-Index is, was es hierbei sein sollte (oder sollen mehr auf einer Stelle sein dürfen ?), dann kannst du mit
PHP:
do {
  mysql_query("INSERT IGNORE INTO ....");
} while(!mysql_affected_rows());
das einfacher machen, weil du pro Durchlauf eine Abfrage sparst.
Ok, ich wusste irgendwie, dass du oder sonst jemand vorbeikommt, und ne wesentliche einfachere Lösung bringt ;)

Edit: Aber mom mal: Damit verhinderst du doch nur, dass es nicht 2 mal in einer Tabelle vorkommt, aber es darf doch acuh nicht in der andern sein?!
Diesen Aspekt hab ich allerdings übersehn ;)
 
Zuletzt bearbeitet:
*gg* Versteh nur Bahnhof :)

@ theHacker

Was hast du damit gemeint? Und wie wird dann per Zufall ein x und y genommen? So wie ich es bei dir sehe, versucht der so lange, bis es klappt? Kann der nicht sofort im Query gucken was noch frei ist und davon einen per Zufall wählen?

X und Y kann ich nicht zum UNIQUE machen, da es 2 Felder sind. Es gibt ja Einräge mit:

X=0 Y=1 Typ=5
X=0 Y=7 Typ=2
.
.
.
X=0 Y=1800 Typ=1
.
.
.
X=1800 Y=1800 Typ=9
 
Zuletzt bearbeitet:
*gg* Versteh nur Bahnhof :)

@ theHacker

Was hast du damit gemeint? Und wie wird dann per Zufall ein x und y genommen? So wie ich es bei dir sehe, versucht der so lange, bis es klappt? Kann der nicht sofort im Query gucken was noch frei ist und davon einen per Zufall wählen?
Er hat garkeine Zufallszahlen genommen, er hat lediglich gezeigt, wies einfacher geht, die Zahlen hätte er wohl ähnlich wie ich ermittelt.
Das was du vorhast geht natürlich auch. du musst nur, alle x und y Werte, die schon drin sind, abrufen und mit den Zufallszahlen vergleichen.
 
Was würde denn am schnellsten Laufen ohne viele Query's?

X und Y geht bis jewils 1000.

Es sind ca. 34.000 Einträge drin. :-/ Das würde ja Jahres dauern bis das Script mal durch ist. Leider wird das Script später sehr oft aufgerufen :((
 
Zuletzt bearbeitet:
Am wenigsten Querys würde es natürlich brauchen, wie oben beschreiben, alle Planeten abzurufen und in ein Array zu packen. Da muss dann aber anstelle der Querys immer das Array durchlaufen werden, um zu schauen, ob es schon da is:

PHP:
$res = mysql_query('SELECT x, y FROM planten');
while($planet = mysql_fetch_object($res))
    $planeten[] = array($planet->x, $planet->y); //erstellt dir das 2dimensionale array mit allen koordinaten der planeten

$insert = false;
do {
    $x = rand(0, 1000);
    $y = rand(0, 1000);
    if(array_search(array($x, $y), $planeten) === false)
        $insert = mysql_query('INSERT INTO `space` (`x`, `y`) VALUES ('.$x.', '.$y.')');
} while(!$insert)

PS: Ein Plural-S bekommt kein Apostroph ;)
 
Zuletzt bearbeitet:
:D

Ich weiß nun nicht mehr weiter. So wie das Script aussieht wird es sehr langsam gehen :D Es muss jedoch sehr schnell sein, denn es wird im Extremfall jede Sekunde ausgeführt.

Oder könnte man die Datenbank irgentwie umbauen, damit es doch wieder schneller gehen würde?
 
:D

Ich weiß nun nicht mehr weiter. So wie das Script aussieht wird es sehr langsam gehen :D Es muss jedoch sehr schnell sein, denn es wird im Extremfall jede Sekunde ausgeführt.

Oder könnte man die Datenbank irgentwie umbauen, damit es doch wieder schneller gehen würde?
Och, so langsam sieht das doch garnet aus, wie wärs, wenn du es einfach mal testest? Es werden immerhin nur 2 Querys abgesetzt und das Durchsuchen des Arrays dauert ja auch keine Ewigkeiten ;)

Zum Thema Umbauen: Du könntest die Koordinaten Bezeichnung von der 2. in die 1. Dimension umlagern. Sprich, du hast einfach Felder von 0 - 1.000.000, die dann zur Anzeige in x und y umgerechnet werden(Division, Modulo), die wären dann nämlich UNIQUE ;) Hat natürlich den Nachteil, dass du schlecht nach Objekten in der Umgebung suchen kannst. Du kannst dann aber auch beide Bezeichnungen in der DB speichern, also x, y und die eindeutige Nummer.
 
Zuletzt bearbeitet:
Das könnte man Theoretisch machen. Also nur ein Table mit den ganzen belegten Feldern drin. :) Nur dann müsste ich immer alles 2x ändern :D
 
Das wo du meinst würde nichts bringen, da es nur in einer Tabelle ist, trotzdem hätte man dann sehr viele Abfragen :D
 
Öhm... gute Frage *fg*

Nee,
ich habe bei ship noch paar Spalten die ich gut brauchen werde, und die haben bei den Planten nix verloren / Sie wären dann nur leer :D
 
Also ich würde das ganze so aufbauen:
Eine Tabelle mit den Koordinaten und anderen Daten, die bei allen Objekten gleich sind: id | x | y | nummer | besitzer (zB)
Dann würde ich andere Tabellen anlegen, für zB Planeten, Schiffe, Monde,... in denen dann die einzelnen Eigenschaften drinstehen und ein Feld, dass die zugehörige ID in der oben genannten Tabelle beinhaltet.
So brauchst du net 2x zu ändern (nur beim löschen und eintragen) und hast trotzdem alle belegten Felder in einer Tabelle.
 
Also so z. B. :

world
id | x | y | typ(planet, schiff ..)

planeten
id | world_id | besitzer | temperatur ....

schiffe
id | world_id | besitzer | angriff | verteidigung | energy ...


Dann müsste ich am besten World erst ein mal füllen als frei, also 1.000.000 Einträge. Dann kann man nach belieben Planeten usw. verteilen.

Und nun zum zufälligen Verteilen dann "SELECT x,y WHERE typ = 'frei' ORDER BY RAND() LIMIT 1".
Wie müssten dann die ganzen Tabellen aufgebaut sein? Also Typ(int, smallint...), Index usw.? Habe mit so großen Datenbanken noch nichts gemacht.
Ich will auch nicht, das ich nun am Anfang einen Fehler mache, den ich dann die ganze Zeit drin habe und es total langsam geht. :)

EDIT: Aus dem Typ könnte man eigentlich ja ein ENUM machen. Wie wirkt sich dies auf die Geschwindigkeit aus?
 
Also so z. B. :

world
id | x | y | typ(planet, schiff ..)

planeten
id | world_id | besitzer | temperatur ....

schiffe
id | world_id | besitzer | angriff | verteidigung | energy ...


Dann müsste ich am besten World erst ein mal füllen als frei, also 1.000.000 Einträge. Dann kann man nach belieben Planeten usw. verteilen.

Und nun zum zufälligen Verteilen dann "SELECT x,y WHERE typ = 'frei' ORDER BY RAND() LIMIT 1".
Wie müssten dann die ganzen Tabellen aufgebaut sein? Also Typ(int, smallint...), Index usw.? Habe mit so großen Datenbanken noch nichts gemacht.
Ich will auch nicht, das ich nun am Anfang einen Fehler mache, den ich dann die ganze Zeit drin habe und es total langsam geht. :)
Japp, genau so meine ich das. Nur musst du freie Plätze ja nicht unbedingt eintragen, aber wenns dir einfacher erscheint isses gut ;)
Welche Datentypen du nehmen sollst, kann ich dir leider nicht so genau sagen, hab mir da noch kaum Gedanken drum gemacht (aus dem gleichen Grund wie du)
Schau dir am besten bei Zahlen einfach die Grenzen an und such dann den Typ aus, in den das, was später drin stehn wird passt (für x und y sollte smallint langen; id würde ich auf int setzen und natürlich als key und unique)
Wenn du ein Feld machen willst, das quasi einen booleschen Wert (0, 1) beinhalten soll, nimm char(1) und nicht smallint, hab ich mir mal sagen lassen ;)