This is an old revision of the document!
This page is not fully translated, yet. Please help completing the translation.
(remove this paragraph once the translation is finished)
All the examples in this area are carried out in the new style of WB 2.8.4. For older versions mostly you have to replace $oDb by $database, $oDb→TablePrefix by TABLE_PREFIX, and →doQuery() by →query()
This is almost a whole chapter of its own. So the best thing to do first is to establish the most basic rules:
SQL statements should be built up visually such that they can be read and understood quickly and easily. The line by line breakdown by action keywords is very useful here. If a line is too long (Coding Standards) then spread with indentation on multiple lines. In the context of selecting fields it should be noted that the server can provide complete records (SELECT *) significantly faster than a rule containing a long list of individual fields. To demonstrate the structure of statements, in the following there are some examples of the most important types of queries.
Each of all the four examples give back a result-object with all records of the visible sections of a page at the current time.
$oResult = $oDb->doQuery("SELECT section_id, page_id, position, module, block, publ_start, publ_end FROM ".TABLE_PREFIX."sections where page_id= $iPageId and (publ_start = 0 OR publ_start <= $iTimestamp ) and (publ_end = 0 OR publ_end >= $iTimestamp ) order by block, position");
$sql = 'SELECT `section_id`, `page_id`, `position`, `module`, `block`, `publ_start`, `publ_end` FROM `'.$oDb->TablePrefix.'sections` '; $sql .= 'WHERE `page_id`='.$iPageId.' AND (`publ_start`=0 OR `publ_start`<='.$iTimestamp.') AND (`publ_end`=0 OR `publ_end`>='.$iTimestamp.') '; $sql .= 'ORDER BY `block`, `position`'; $oResult = $oDb->doQuery($sql);
$sql = 'SELECT `section_id`, `page_id`, `position`, `module`, ' . '`block`, `publ_start`, `publ_end` ' . 'FROM `'.$oDb->TablePrefix.'sections` ' . 'WHERE `page_id`='.$iPageId.' ' . 'AND (`publ_start`=0 OR `publ_start`<='.$iTimestamp.') ' . 'AND (`publ_end`=0 OR `publ_end`>='.$iTimestamp.') ' . 'ORDER BY `block`, `position`'; $oResult = $oDb->doQuery($sql);
$sql = 'SELECT * FROM `'.$oDb->TablePrefix.'sections` ' . 'WHERE `page_id`='.$iPageId.' ' . 'AND (`publ_start`=0 OR `publ_start`<='.$iTimestamp.') ' . 'AND (`publ_end`=0 OR `publ_end`>='.$iTimestamp.') ' . 'ORDER BY `block`, `position`'; $oResult = $oDb->doQuery($sql);
Let's have a short quiz now:
Question: Which of the examples are easier to read, to understand and to modify if required? 1&2 or 3&4 ??
With this query, you can not go wrong… except for the case that you provide the wrong deletion criteria.
But again: First build the statement and save it in a variable and then passe it to the query method.
$sql = 'DELETE FROM `'.$oDb->TablePrefix.'users`' . 'WHERE `user_id`='.$iUserId; $oDb->doQuery($sql);
Normally, records should be deleted only by specifying their record ID.
In diesem Bereich wird es langsam interessant. Es gibt mehrere verschiedene Arten die Statements für INSERTs und UPDATEs aufzubauen. Speziell im Bereich der Werteübergabe.
Bei allen Arten von INSERTs gilt jedoch die SQL-Strikt Regel, dass allen Feldern eines Datensatzes Werte zugewiesen werden müssen. Ausgenommen hiervon sind nur die Felder, die in der Tabelle bereits mit einem Default-Wert vordefiniert sind.
Immer wenn Daten in die Datenbank geschrieben werden sollen, sind bestimmte Sicherheitsregeln zu beachten.
Im Umfeld von WebsiteBaker ist für INSERT und UPDATE Statements ausschließlich die 'SET'-Methode zur Werteübergabe zulässig!
Erst ein Beispiel wie ein Statement (obwohl syntaktisch richtig) nicht aussehen darf:
// das ist übrigens ein Original-Statement aus WB-2.8.3-SP1 'add user' $sql = "INSERT INTO ".TABLE_PREFIX."users (group_id,groups_id,active,username,password,display_name,home_folder,email,timezone, language) VALUES ('$group_id', '$groups_id', '$active', '$username','$md5_password','$display_name','$home_folder','$email','-72000', '$default_language')";
Das selbe Statement jetzt nach den zuvor beschriebenen Regeln:
$sql = 'INSERT INTO `'.$oDb->TablePrefix.'users` ' . 'SET `group_id`='.$group_id.', ' . '`groups_id`=\''.$oDb->escapeString($groups_id).'\'`, ' . '`active`='.($active ? 1 : 0).', ' . '`username`=\''.$oDb->escapeString($username).'\', ' . '`password`=\''.$oDb->escapeString($md5_password).'\', ' . '`display_name`=\''.$oDb->escapeString($display_name).'\', ' . '`home_folder`=\''.$oDb->escapeString($home_folder).'\', ' . '`email`=\''.$oDb->escapeString($email).'\', ' . '`timezone`='.(int)-72000.', ' . '`language`=\''.$oDb->escapeString($default_language).'\'';
Ein UPDATE sieht im Prinzip genau so aus:
$sql = 'UPDATE `'.$oDb->TablePrefix.'users` ' . 'SET `display_name`=\''.$oDb->escapeString($sNewDisplayName).'\', ' . '`active`=1 ' . 'WHERE `user_id`='.$iUserId;
Ein großer Vorteil der SET-Methode ist neben der Übersichtlichkeit und der leichten Änderbarkeit, der Umstand, dass auf die Reihenfolge der Felder keine Rücksicht genommen werden muss. Es genügt einfach, dass alle benötigten Felder vorhanden sind. Diese Vorteile wiegen weit stärker als die dafür zusätzlich benötigte Zahl an Zeilen.
(mySQL spezifische Erweiterung zu ANSI-SQL)
Wie überall gibt es fast keine Regel ohne Ausnahme.
REPLACE funktioniert primär identisch wie INSERT. Mit einem kleinen, jedoch entscheidenden Unterschied:
Wird versucht, einen Datensatz einzufügen, der einen Index-Konflikt mit einem bestehende Datensatz auslöst, wird der Prozess nicht abgebrochen, sondern der bestehende, alte Datensatz wird gelöscht und der neue eingefügt.
REPLACE ist grundsätzlich nicht für Tabellen geeignet, die einen Autoincrement-Wert nutzen, der in einer anderen Tabelle als Fremdschlüssel benutzt wird.
Der WebsiteBaker-Core benutzt dieses SQL-Kommando z.B. zum Eintragen und Ändern von Werten in die Tabelle `settings`. Damit das Ganze funktioniert, sind gewisse Anforderungen an die Tabelle zu erfüllen.
-- Structure of table '{TABLE_PREFIX}settings' -- CREATE TABLE IF NOT EXISTS `{TABLE_PREFIX}settings` ( `name` VARCHAR(255){FIELD_COLLATION} NOT NULL, `value` text{FIELD_COLLATION} NOT NULL, PRIMARY KEY (`name`) ){TABLE_ENGINE};
Im Statement muss zwingend ein Wert für das Feld mit dem PRIMARY_KEY oder UNIQUE_KEY übergeben werden. Auch der Aufbau des Statements weicht vom normalen 'SET' - Standard ab, dafür können als Ausgleich auch mehrere Datensäte in einem Zug geändert werden:
$sql = 'REPLACE INTO `'.$oDb->TablePrefix.'settings` (`name`, `value`) ' . 'VALUES (\''.$sName_1.'\', \''.$oDb->escapeString($sValue_1).'\'), ' // Datensatz 1 . '(\''.$sName_2.'\', \''.$oDb->escapeString($sValue_2).'\'), ' // Datensatz 2 . '(\''.$sName_3.'\', \''.$oDb->escapeString($sValue_3).'\')'; // Datensatz 3 if (!$oDb->doQuery($sql)) { $retval = false; }