2016-04-08 1 views
0

MySLQ novice ici. J'essaie d'écrire une requête pour faire pivoter une grande table de données météorologiques. Par là, je veux dire ce qui suit. J'ai une table "weatherData" avec trois colonnes: 1. "timeStamp", 2. "stationID" (ID des différentes stations météorologiques) et 3. "température" (température mesurée par station respective à l'heure respective). Je voudrais que ma requête retourne comme première colonne "timeStamp" et ensuite n colonnes nommées comme les ID de station contenant les températures mesurées (n est le nombre de stations qu'il y a). Il y a un grand nombre de stations (n ​​est autour de 4000) et les températures sont enregistrées en 5 min. intervalles de plus de 2,5 ans, "weatherData" a environ 7 millions de lignes.Erreur de requête MySQL dynamique

La première chose que j'ai essayé générait les colonnes « manuellement »:

SELECT 
    timeStamp, 
    SUM(CASE WHEN stationID=1253 THEN temperature ELSE 0 END) AS '1253', 
    SUM(CASE WHEN stationID=1254 THEN temperature ELSE 0 END) AS '1254', 
    SUM(CASE WHEN stationID=1255 THEN temperature ELSE 0 END) AS '1255', 
    SUM(CASE WHEN stationID=1256 THEN temperature ELSE 0 END) AS '1256', 
    SUM(CASE WHEN stationID=1257 THEN temperature ELSE 0 END) AS '1257', 
    SUM(CASE WHEN stationID=1258 THEN temperature ELSE 0 END) AS '1258' 
FROM weatherData 
GROUP BY timeStamp 

Cela fonctionne comme prévu, mais en ajoutant toutes les stations rendrait une longue requête. J'ai ensuite essayé de générer dynamiquement la requête comme suit:

SET @query = NULL; 
SELECT GROUP_CONCAT(
    DISTINCT CONCAT( 
    'SUM(', 
     'CASE WHEN stationID = ',stationID,' THEN temperature ELSE 0 END', 
    ') AS "',stationID,'"' 
)  
) 

INTO @query 
FROM weatherData; 

SET @query = CONCAT(
    'SELECT temperature, ',@query, 
    'FROM weatherData', 
    'GROUP BY timeStamp' 
); 

PREPARE stmt FROM @query; 
EXECUTE stmt; 
DEALLOCATE PREPARE stmt; 

Cela me donne l'erreur suivante:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'weatherData GROUP BY timeStamp' at line 1

Ce qui est étrange est que lorsque je produis une table plus petite qui ne contient que les données jusqu'à 14 stations météo de weatherData et exécuter la requête "dynamique" ci-dessus sur cette petite table fonctionne parfaitement bien. Donc, cela ne marche pas quand j'inclus des données de plus de 14 stations et cela ne dépend pas des stations particulières qui sont incluses. La requête "manuelle" fonctionne toujours quel que soit le nombre de stations incluses. Quel est le problème ici?

La deuxième chose étrange est que la première requête prend beaucoup plus de temps en incluant (les mêmes) 14 stations, j'aurais pensé que ces requêtes sont équivalentes. J'utilise la dernière version gratuite "Toad for MySQL".

+1

Ajouter un espace avant 'weatherData' DE –

+0

Vous pouvez déposer' SET @query = NULL; 'si vous ne réglez ce sera NULL, et non implicitement lié à l'erreur – Mihai

Répondre

0

Pour l'instant vous avez un problème avec les espaces manquants. Ajoutez-les avant les clauses FROM et GROUP BY.

SET @query = CONCAT(
    'SELECT temperature, ',@query, 
    ' FROM weatherData', -- added space 
    ' GROUP BY timeStamp' -- added space 
); 

Bien que, si votre GROUP_CONCAT grandirons assez grand (> 1024 caractères) et votre réglage est par défaut, il tronquera votre variable @query et peut provoquer une erreur avec votre requête. Pour vérifier si c'est le cas - lorsque votre dynamique s'agrandit, ajoutez un SELECT @query à des fins de débogage. Je crois que ma réponse récente va résoudre vos problèmes. J'ai couvert les problèmes avec la longueur maximale GROUP_CONCAT ainsi que le débogage de la requête dynamique en examinant la chaîne avant son exécution.

Pour le voir cliquez ici: MySQL Dynamic Pivot Query with over 3000 columns

+0

J'ai effectivement les espaces dans ma requête, pour une raison quelconque, je les avais supprimés dans mon message. Ajout de la ligne SET SESSION group_concat_max_len = 1000000; résout mon problème original mais maintenant je reçois une erreur "too many columns". Je comprends qu'aucune table ne devrait avoir autant de colonnes, mais pourquoi une requête ne devrait-elle pas être capable de retourner ceci? – salvador