Mediane in MySQL (Mediane in MySQL), Lektion, Seite 723363
https://www.purl.org/stefan_ram/pub/mediane_mysql (Permalink) ist die kanonische URI dieser Seite.
Stefan Ram

Mediane in MySQL

Einleitung

OLAP Online Analytical Processing: Durchführung komplexer Analysevorhaben mit relative schnellen (“online ”) Systemantworten

OLTP Verarbeitung von Transaktionen (nicht nach Sammlung in einem „Batch“) mit schneller (“online ”) Umsetzung im System

MySQL  ist wohl mehr auf OLTP ausgerichtet als auf OLAP!

Das Ziel dieses SQL-Kurses ist es, die Kursteilnehmer so vertraut mit SQL  zu machen, daß sie in der Lage sind, die von ihnen gewünschte Definition des Medians selber  mit SQL  zu formulieren. Es geht hier nicht darum, daß der Dozent solche Dinge für sie programmiert, denn das wäre eine andere Vertragsart - kein Unterricht, sondern Auftragsprogrammierung.

Es gibt in SQL  leider keine Standardfunktion mit welcher der Median einer Stichprobe direkt notiert werden kann. Dies liegt vielleicht teilweise daran, daß es verschiedene Definitionen für den Median gibt und viele Anwendungsarten den Median nicht benötigen, so daß man es dem Programmierer überlassen wollte, den Median bei Bedarf selber zu programmieren.

Die Formulierung des Medians mit SQL ist tatsächlich nicht so einfach, daß sie bereits früh im Kurs behandelt werden kann. Eine der einfacheren Lösungswege ist:

WARNINGS; SET sql_mode = 'ANSI,TRADITIONAL';
DROP SCHEMA S; CREATE SCHEMA S; USE S;
CREATE TABLE STICHPROBE ( STICHPROBE INTEGER, VALUE INTEGER );
DELETE FROM STICHPROBE;
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 1, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 2, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 3, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 4, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 5, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 6, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 7, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 8, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 9, 1 );
SELECT * FROM STICHPROBE;


SELECT STICHPROBE.VALUE AS MEDIAN
FROM STICHPROBE, STICHPROBE AS OTHER
GROUP BY STICHPROBE.VALUE
HAVING SUM( SIGN( 1 - SIGN( STICHPROBE.VALUE - OTHER.VALUE )))
= FLOOR( ( COUNT( * )+ 1 )/ 2 );

Ein Nachteil dieser Lösung ist, daß sie relativ langsam  ist (wohl quadratisch), da alle Werte des kartesischen Quadrates verwendet werden.

Außerdem zeigt das obige Beispiel, daß diese einfache Lösung auch nicht immer einen Median findet.

Die beste Lösungsweg

Beste Lösung: Ermittlung mit prozeduralem Klienten  oder SPSS  (ODBC ) oder R, da deklaratives SQL  hierfür keine effizienten Lösungen erlaubt (die besten Lösungen sind hier nur quadratisch). Bei kleinen Stichprobenmengen sollte es aber gehen.

Es gibt aber auch prozedurales  SQL.

WARNINGS; SET sql_mode = 'ANSI,TRADITIONAL';
DROP SCHEMA S; CREATE SCHEMA S; USE S;
CREATE TABLE STICHPROBE ( STICHPROBE INTEGER, VALUE INTEGER );
DELETE FROM STICHPROBE;
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 1, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 2, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 3, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 4, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 5, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 6, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 7, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 8, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 9, 1 );
SELECT * FROM STICHPROBE;
SELECT STICHPROBE, VALUE FROM STICHPROBE;

DROP PROCEDURE IF EXISTS MEDPROC; -- based on publications by Jon LaBelle and Joe Wynne
DELIMITER |
CREATE PROCEDURE MEDPROC( tbl CHAR( 64 ), col CHAR( 64 ), OUT result DOUBLE )
BEGIN

DECLARE arg CHAR( 64 );
SET @source = CONCAT( 'SELECT ( ( COUNT( * ))/ 2 ) INTO @half FROM ', tbl );
PREPARE statement FROM @source;
EXECUTE statement;
DROP PREPARE statement;

SET @offset = CONVERT( FLOOR( @half ), SIGNED );
IF @offset = @half THEN
BEGIN
SET @offset = @offset - 1;
SET @rowcount = 2;
SET arg = CONCAT( 'AVG(', col, ')' );
END;
ELSE
BEGIN
SET @rowcount = 1;
SET arg = col;
END;
END IF;

SET @source = CONCAT
(

'SELECT ', arg,
' INTO @res FROM ',
' ( SELECT ', col,
' FROM ', tbl,
' ORDER BY ', col,
' LIMIT ?, ?',
' )',
'as tmp'
);
SELECT CONCAT( @source ); -- debug print!
PREPARE statement FROM @source;
EXECUTE statement USING @offset, @rowcount;
DROP PREPARE statement;
SET result = @res;

END;
|
DELIMITER ;

CALL MEDPROC( 'STICHPROBE', 'VALUE', @MEDVAL );

SELECT @MEDVAL;

Der Median nach Behrends 

Es gibt verschiedene Definitionen für den Begriff „Median“ in der Literatur. Hier eine von Behrends :

Eine Zahl ‹ m › heißt ein Median  einer Stichprobe ‹ x ›, wenn mindestens die Hälfte der ‹ xᵢ › größer-gleich x und gleichzeitig mindestens die Hälfte der ‹ xᵢ › kleiner-gleich x ist. (Ehrhard Behrends , 2010-07-15)

Eine deklarative Implementation des Behrends -Median

WARNINGS; SET sql_mode = 'ANSI,TRADITIONAL';
DROP SCHEMA S; CREATE SCHEMA S; USE S;
CREATE TABLE STICHPROBE ( STICHPROBE INTEGER, VALUE INTEGER );
DELETE FROM STICHPROBE;
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 1, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 2, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 3, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 4, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 5, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 6, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 7, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 8, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 9, 1 );
SELECT STICHPROBE, VALUE FROM STICHPROBE;
CREATE OR REPLACE VIEW STAT AS
SELECT
STICHPROBE,
VALUE,

( SELECT
COUNT( * )
FROM
STICHPROBE AS STICHPROBE1 ) / 2 AS HALF,

( SELECT
COUNT( VALUE )
FROM
STICHPROBE AS STICHPROBE1
WHERE
STICHPROBE1.VALUE <= STICHPROBE.VALUE ) AS SMALLER,

( SELECT
COUNT( VALUE )
FROM
STICHPROBE AS STICHPROBE1
WHERE
STICHPROBE1.VALUE >= STICHPROBE.VALUE ) AS LARGER

FROM STICHPROBE;
SELECT DISTINCT VALUE FROM STAT WHERE SMALLER >= HALF AND LARGER >= HALF;
CREATE VIEW MEDIAN AS SELECT DISTINCT VALUE AS MEDIAN FROM STAT WHERE SMALLER >= HALF AND LARGER >= HALF;

SELECT MEDIAN FROM MEDIAN;

+--------+
| MEDIAN |
+--------+
| 1 |
+--------+

DELETE FROM STICHPROBE;
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 1, 1 );
SELECT MEDIAN FROM MEDIAN;
+--------+
| MEDIAN |
+--------+
| 1 |
+--------+

DELETE FROM STICHPROBE;
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 1, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 2, 2 );
SELECT MEDIAN FROM MEDIAN;

+--------+
| MEDIAN |
+--------+
| 1 |
| 2 |
+--------+

DELETE FROM STICHPROBE;
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 1, 1 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 2, 2 );
INSERT INTO STICHPROBE ( STICHPROBE, VALUE ) VALUES ( 3, 3 );
SELECT MEDIAN FROM MEDIAN;

+--------+
| MEDIAN |
+--------+
| 2 |
+--------+

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 stefanram723363 stefan_ram:723363 Mediane in MySQL Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd723363, slrprddef723363, 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/mediane_mysql