Routinen in MySQL (Routinen in MySQL), Lektion, Seite 722525
https://www.purl.org/stefan_ram/pub/routinen_mysql (Permalink) ist die kanonische URI dieser Seite.
Stefan Ram
SQL-Kurs

Routinendefinitionen in MySQL

SQL ist eine deklarative  Sprache. Man schreibt nieder, welche Information man wünscht. Aus den Abfragen erzeugt der Abfrageoptimierer einen Abfrageplan, der die einzelnen Schritte enthält, die nötig sind, um das Ergebnis der Abfrage zu ermitteln. Der Abfrageoptimierer kennt die Stärken und Schwächen des verwendeten Datenkbanksystems oft gut und kann den Abfrageplan daher so erstellen, daß er oft sehr schnell  abgearbeitet werden kann.

Würde man eine Information suchen, indem man mit einer prozeduralen  Sprache auf die Basistabellen zugreift und dann die Daten mit der prozeduralen  Sprache miteinander verknüpft, so würde dies in der Regel langsamer  und fehlerträchtiger  sein als bei Verwendung von SQL-Abfragen. Deswegen soll man für das was das deklarative SQL gut kann bevorzugt das deklarative SQL verwenden (also SELECT-Abfragen und View-Definitionen). Prozeduren sollten nur  eingesetzt werden, um etwas zu erledigen, das mit SQL schlecht geht, wie beispielsweise die Erzeugung von Zeilennummern zur Ausgabe einer durchnumerierten Liste. Wenn man eine Abfrage in deklarativem SQL geschrieben hat, und dann Teile davon durch Funktionen oder Prozeduren ersetzt, die in SQL geschrieben sind, dann wird die Abfrage dadurch in der Regel deutlich langsamer.

Normalerweise verwendet jedes Datenbanksystem, das es erlaubt Prozeduren zu schreiben, eine eigene  Prozedursprache dafür und nicht die erst 2003 standardisierte Standard-Prozedursprache von SQL 2003. Ausgerechnet MySQL ist jedoch eine Ausnahme: Die MySQL-Prozedursprache ist relativ standardkonform. Leider bedeutet dies derzeit aber noch nicht, daß man in MySQL geschriebene Prozeduren leicht auf andere Datenbanksysteme übertragen kann, da diese noch nicht standardkonform sind. Wenn man aber überhaupt  Prozeduren schreiben will oder muß, dann ist gerade MySQL eine gute Wahl dafür, weil die Prozedursprache von MySQL dem Sprachstandard recht nahekommt. Alternativ können Prozeduren aber auch in Programmiersprachen wie Java  oder PHP  geschrieben werden, von denen aus ebenfalls auf MySQL-Datenbanken zugegriffen werden kann.

Systemvariablen

Systemvariablen (global und session)

Einiges dazu wurde schon in Lektion 723195 „Einstellungen “ gesagt.

Die folgende Ausgabe von »@@sql_mode« nach »SET sql_mode = 'ANSI';« zeigt, welche anderen Einstellungen die Einstellung »ANSI« umfaßt.

Konsole
SET sql_mode = 'ANSI'; SELECT @@sql_mode;
+-------------------------------------------------------------+
| @@sql_mode |
+-------------------------------------------------------------+
| REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI |
+-------------------------------------------------------------+

Benutzervariablen

Benutzervariablen beginnen mit @ und gelten nur für eine Sitzung

SET @v = …

SET @v = f( @v )

SET @v := …

SELECT @v := …

SELECT col INTO @v …

Im letzten Fall sollte nur eine Zeile zurückgegeben werden.

Lokale Variable

Mit DECLARE in Routine

Einfache Funktionsdefinitionen

mysql> CREATE FUNCTION R.NAND( A BOOL, B BOOL )RETURNS BOOL DETERMINISTIC RETURN NOT( A AND B );
Query OK, 0 rows affected (0.33 sec)

mysql> SELECT R.NAND( 0, 1 );
+-------------+
| R.NAND(0,1) |
+-------------+
| 1 |
+-------------+
1 row in set (0.19 sec)

mysql> DROP FUNCTION R.NAND;
Query OK, 0 rows affected (0.00 sec)

CREATE FUNCTION hello( name VARCHAR(20) )RETURNS VARCHAR(30)

BEGIN

RETURN CONCAT('Hello ', name);

END

SELECT sayHello('peter');

CREATE FUNCTION reorderCostFn (a INT) RETURNS DECIMAL(8,2)

BEGIN

SELECT IFNULL(sum(price*(a-q)), 0) INTO @tmp

FROM products

WHERE q < a;

RETURN @tmp;

END//

Prozedurdefinition

CREATE PROCEDURE example(parameters)

BEGIN

DECLARE v1 type [DEFAULT value];

statement1;

....

statementN;

END

CREATE PROCEDURE example()

SELECT 1;

CALL example;

Routinendefinitionen mit Semikola

Manche Funktionsdefinitionen enthalten Semikola. Dann muß ein andere Kommandoterminierer eingestellt werden.

DELIMITER $$

CREATE FUNCTION …

$$

DELIMITER ;

CREATE PROCEDURE beginExample()

BEGIN

SELECT 1;

SELECT 2;

END

CREATE PROCEDURE example (IN a INT, OUT b DECIMAL(6,2))

BEGIN

SELECT IFNULL(sum(price*(a-field)), 0) INTO b

FROM example

WHERE field < a;

END

CALL example(5000, @tmp);

SELECT @tmp;

Kontrollstrukturen

IF condition THEN statements; [ELSEIF condition THEN statements;] [ELSE statements;] END IF;

CASE caseValue WHEN value1 THEN statements; WHEN value2 THEN statements; ...... [ELSE sStatements;] END CASE;

CASE WHEN condition1 THEN statements; WHEN condition2 THEN statements; ....... [ELSE statements;] END CASE;

REPEAT statements UNTIL condition REPEAT statements; UNTIL condition END REPEAT;

WHILE condition is true DO statements WHILE condition DO statements; END WHILE;

LOOP statements; LEAVE label; END LOOP [end_label]; = break

label: LOOP ...... ITERATE label; ...... END LOOP = continue

IFNULL(value, nullResult) : nullResult, wenn value NULL, sonst value

ISNULL(value) : true wenn null

NULLIF(value1, value2) : null wenn beide gleich

Beispiel

Die folgende Prozedur soll eine SELECT-Abfrage für verschiedene Werte ausprobieren.

DROP SCHEMA S20160429;
CREATE SCHEMA S20160429;
USE S20160429;

CREATE TABLE TBL_SHIFT
( SHIFT_ID SERIAL,
SHIFT_NAME VARCHAR( 255 ) UNIQUE NOT NULL,
SHIFT_START CHAR( 8 ) NOT NULL,
SHIFT_END CHAR( 8 ) NOT NULL );

INSERT INTO TBL_SHIFT ( SHIFT_NAME, SHIFT_START, SHIFT_END ) VALUES ( 'Morning', '09:00:00', '13:00:00' );
INSERT INTO TBL_SHIFT ( SHIFT_NAME, SHIFT_START, SHIFT_END ) VALUES ( 'Evening', '13:00:00', '16:15:00' );
INSERT INTO TBL_SHIFT ( SHIFT_NAME, SHIFT_START, SHIFT_END ) VALUES ( 'Night', '16:01:00', '09:00:00' );

DELIMITER $$
CREATE PROCEDURE TRYOUT()
BEGIN
DECLARE X INT DEFAULT 0;
DECLARE CURRENT_TIME_ VARCHAR( 255 ) DEFAULT '';
SET X = 1;
WHILE x <= 24 DO
SET CURRENT_TIME_ = CONCAT( IF( X < 10, '0', '' ), X, ':00:00' );
SELECT
*, CURRENT_TIME_
FROM
TBL_SHIFT
WHERE IF
( SHIFT_START <= SHIFT_END,
CURRENT_TIME_ BETWEEN SHIFT_START AND SHIFT_END,
CURRENT_TIME_ BETWEEN SHIFT_START AND '24:00:00' OR
CURRENT_TIME_ BETWEEN '00:00:00' AND SHIFT_END );
SET X = X + 1;
END WHILE;
END
$$
DELIMITER ;

CALL TRYOUT();

DELIMITER $$

CREATE FUNCTION Z( X VARCHAR ( 255 ) )
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE V INT DEFAULT 0;
SET V = 0;
SELECT ORT INTO V FROM ORT WHERE NAME = X;
RETURN V;
END$$

DELIMITER ;

Beispiel »FILLPROC«

Main.sql

WARNINGS; SET sql_mode = 'ANSI,TRADITIONAL';

DROP SCHEMA IF EXISTS Sq9i7vl$1bd4$_20190421182933;
CREATE SCHEMA Sq9i7vl$1bd4$_20190421182933;
USE Sq9i7vl$1bd4$_20190421182933;

CREATE TABLE DIET
( DIET SERIAL PRIMARY KEY, ENGLISH VARCHAR( 50 ) NOT NULL UNIQUE );

INSERT INTO DIET( ENGLISH )VALUES( 'vegan' );
INSERT INTO DIET( ENGLISH )VALUES( 'vetarian' );

CREATE TABLE FOODSTYLES
( FOODSTYLE SERIAL PRIMARY KEY,
DIET BIGINT UNSIGNED NOT NULL,
INGREDIENT SMALLINT NOT NULL,
FOREIGN KEY( DIET )REFERENCES DIET( DIET ));

DELIMITER $$

DROP PROCEDURE IF EXISTS FILLPROC$$

CREATE PROCEDURE FILLPROC()
BEGIN

DECLARE I INTEGER;
DECLARE VEGAN_INGREDIENTS JSON;

SET I = 0;
SET VEGAN_INGREDIENTS = JSON_ARRAY( 4, 2, 8, 9, 3 );

WHILE I < JSON_LENGTH( VEGAN_INGREDIENTS )DO
INSERT INTO FOODSTYLES( DIET, INGREDIENT )
VALUES
( 1, JSON_EXTRACT( VEGAN_INGREDIENTS, CONCAT( '$[', I, ']' )));
SET I = I + 1;
END WHILE;

END$$

DELIMITER ;

CALL FILLPROC;

SELECT FOODSTYLE, ENGLISH, INGREDIENT FROM FOODSTYLES INNER JOIN DIET USING( DIET );

transcript
+-----------+---------+------------+
| FOODSTYLE | ENGLISH | INGREDIENT |
+-----------+---------+------------+
| 1 | vegan | 4 |
| 2 | vegan | 2 |
| 3 | vegan | 8 |
| 4 | vegan | 9 |
| 5 | vegan | 3 |
+-----------+---------+------------+

Die Wandlung von »4, 2, 8, 9, 3« in eine Spalte ist gewissermaßen das Gegenteil von »GROUP_CONCAT«.

Seiteninformationen und Impressum   |   Mitteilungsformular  |   "ram@zedat.fu-berlin.de" (ohne die Anführungszeichen) ist die Netzpostadresse von Stefan Ram.   |   Eine Verbindung zur Stefan-Ram-Startseite befindet sich oben auf dieser Seite hinter dem Text "Stefan Ram".)  |   Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram. Schlüsselwörter zu dieser Seite/relevant keywords describing this page: Stefan Ram Berlin slrprd slrprd stefanramberlin spellched stefanram722525 stefan_ram:722525 Routinen in MySQL Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd722525, slrprddef722525, PbclevtugFgrsnaEnz Erklärung, Beschreibung, Info, Information, Hinweis,

Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram.
https://www.purl.org/stefan_ram/pub/routinen_mysql