Diese ziemlich schwierig ist, vielleicht gibt es einen besseren Weg, es zu tun, aber hier ist meine zwei Cent, beachten Sie, dass die gruppierten Spaltennamen in MySQL unmöglich ist, als Es gibt nur die Beziehung zwischen Spalten und Spaltennamen ist 1: 1.
Im Folgenden finden Sie einen Code, der Testdaten generiert und dann eine Prozedur erstellt, die auf dynamischem SQL basiert, um die Abfrage zu generieren, die erforderlich ist, um die Ergebnisse zurückzugeben, die ebenfalls dynamisch ausgeführt werden. Beachten Sie, dass der Code ohne Fehler ausgeführt werden sollte, DROP-Anweisungen jedoch kommentiert sind, um unerwünschte Schäden an Ihrer vorhandenen Struktur zu vermeiden. Die Prozedur RANDBETWEEN wird in der letzten gespeicherten Prozedur nicht benötigt, wird aber zum Generieren von Testdaten verwendet.
#DROP TABLE IF EXISTS sales;
CREATE TABLE `sales` (
`model` varchar(64) DEFAULT NULL,
`price` int DEFAULT NULL,
`quantity` int(2) DEFAULT NULL,
`date` datetime
);
SET @VMinModel := 1;
SET @VMaxModel := 5;
SET @VMinPrice := 10;
SET @VMaxPrice := 100;
SET @VMinQuantity := 1;
SET @VMaxQuantity := 10;
SET @VMinTime := UNIX_TIMESTAMP('2016-01-01');
SET @VMaxTime := UNIX_TIMESTAMP('2016-12-31');
#DROP FUNCTION RANDBETWEEN;
DELIMITER $
CREATE FUNCTION RANDBETWEEN(VMin INTEGER UNSIGNED, VMax INTEGER UNSIGNED) RETURNS INTEGER UNSIGNED
DETERMINISTIC
BEGIN
RETURN ROUND(RAND() * (VMax - VMin) + VMin);
END$
DELIMITER ;
INSERT INTO `sales` SELECT RANDBETWEEN(@VMinModel, @VMaxModel), RANDBETWEEN(@VMinPrice, @VMaxPrice), RANDBETWEEN(@VMinQuantity, @VMaxQuantity), FROM_UNIXTIME(RANDBETWEEN(@VMinTime, @VMaxTime)) FROM information_schema.COLUMNS LIMIT 1000;
SET @VXDimension := 'model';
SET @VYDimension := 'DATE_FORMAT(date, ''%Y-%m'')';
SET @VMeasures := 'quantity, quantity * price';
SET @VTable := 'sales';
#DROP PROCEDURE IF EXISTS singleDimensionMeltAndCast;
DELIMITER $
CREATE PROCEDURE singleDimensionMeltAndCast (VXDimension CHAR(255), VYDimension CHAR(255), VMeasures CHAR(255), VTable CHAR(255))
BEGIN
SET SESSION group_concat_max_len = 65536;
DROP TEMPORARY TABLE IF EXISTS YDimensionValues;
SET @VCreateYDimensionValueTable := CONCAT('CREATE TEMPORARY TABLE YDimensionValues SELECT DISTINCT ', VYDimension, ' AS YDim1 FROM ', VTable, ' ORDER BY ', VYDimension, ' ASC;');
PREPARE stmt FROM @VCreateYDimensionValueTable;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
DROP TEMPORARY TABLE IF EXISTS Measures;
CREATE TEMPORARY TABLE Measures (measure CHAR(255));
SET @VCreateMeasuresTable := CONCAT('INSERT INTO Measures VALUES(''', REPLACE(VMeasures, ', ', '''), ('''), ''')');
PREPARE stmt FROM @VCreateMeasuresTable;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @VYDimensionSQLFieldsComponent = (SELECT GROUP_CONCAT('SUM(IF(', VYDimension, ' = ''', YDim1, ''', ', measure, ', 0)) `[', YDim1, ' x ', measure, ']`' SEPARATOR ', ') FROM YDimensionValues, Measures WHERE TRUE);
SET @VYDimensionSQLGroupComponent = (SELECT GROUP_CONCAT('IF(', VYDimension, ' = ''', YDim1, ''', ', measure, ', 0)' SEPARATOR ', ') FROM YDimensionValues, Measures WHERE TRUE);
SET @VFinalQuery := CONCAT('SELECT ', VXDimension, ', ', @VYDimensionSQLFieldsComponent, ' FROM ', VTable, ' GROUP BY ', @VYDimensionSQLGroupComponent, ' ORDER BY ', VXDimension, ';');
PREPARE stmt FROM @VFinalQuery;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$
DELIMITER ;
CALL singleDimensionMeltAndCast(@VXDimension, @VYDimension, @VMeasures, @VTable);
Lassen Sie mich wissen, wenn Sie irgendwelche Fragen haben.
Grüße,
James
Geben Sie uns die eigentliche Definition der Tabelle, ist es wirklich in diesem Fall nicht helfen. –
Besser noch, zeigen Sie uns Beispieldaten aus Ihrer Quellentabelle. –
Dies kommt zu der Komplexität, wo ich sagen würde: Tun Sie dies auf der Anwendungsebene, anstatt in einer Abfrage. – Shadow