2017-03-01 1 views
0

quand je lance ci-dessous sélectionner:valeurs d'affichage pour calendrier précis

select name, time, value from table1 where name like '%Z' or '%V' 

Je suis arrivé résultat:

enter image description here

je dois faire deux choses:

) requête sera exécutée toutes les heures, donc si nous avons 12h00.00 plage devrait être entre fr (11 et 12> PM, si sa plage 02.00.00AM sera (01 et 02> AM

) deuxième chose est d'afficher avg (valeur) pour le nom se terminant par '% Z' ou '% V » en une ligne, mais en deux colonnes

Ci-dessous exemple de résultat souhaitable, lorsque requête a été exécutée à 12.00.00 PM:

enter image description here

+0

Vérifiez 'GROUP BY'! – jarlh

+0

Vous voulez réellement afficher la liste des valeurs moyennées, ou simplement la moyenne? La partie de plage de temps est plutôt droite; l'agrégation n'est que légèrement compliquée si vous voulez aussi la liste. (De plus, [envoyez du texte plutôt que des images] (http://meta.stackoverflow.com/a/285557/266304), et les données source comme DDL/DML seraient utiles). –

+0

BTW, votre requête s'exécute-t-elle réellement?!? – jarlh

Répondre

1

Vous demandez trois choses, qui peuvent être considérées comme trois étapes. Obtenir la fenêtre de temps est assez simple, et seulement légèrement compliqué par votre colonne étant un timestamp plutôt qu'une date. Vous avez laissé entendre que cela fonctionnera à l'heure, mais il est possible que ce soit un peu plus tard - peut-être une seconde ou deux? - Il est donc probablement plus sûr de le prendre en compte. Vous pouvez utiliser the trunc() function pour modifier une valeur de date à la précision requise, afin de ne regarder que l'heure actuelle que vous tronqueriez à HH [24]. Vous pouvez alors cast revenir à un horodatage. Et vous pouvez utiliser interval arithmetic pour trouver l'heure avant que:

alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'; 
alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS.FF3'; 
alter session set nls_timestamp_tz_format = 'YYYY-MM-DD HH24:MI:SS.FF3 TZR'; 

select systimestamp, 
    trunc(systimestamp, 'HH24') as a, 
    cast(trunc(systimestamp, 'HH24') as timestamp) as b, 
    cast(trunc(systimestamp, 'HH24') as timestamp) - interval '1' hour as c 
from dual; 

SYSTIMESTAMP     A     B      C      
------------------------------ ------------------- ----------------------- ----------------------- 
2017-03-01 09:25:39.342 +00:00 2017-03-01 09:00:00 2017-03-01 09:00:00.000 2017-03-01 08:00:00.000 

Les commandes sont alter session juste pour contrôler la façon dont les différents types de données sont affichés, à titre de comparaison. (Ne comptez pas sur les paramètres NLS dans votre code réel, utilisez to_char() pour la mise en forme finale des valeurs datetime en tant que chaînes).

Notez que le résultat de la troncature est maintenant une date (A dans cette sortie), donc je l'ai renvoyé à un horodatage (B). La gamme que vous voulez est essentiellement time >= A and time < B. Et vous pouvez utiliser sysdate au lieu de systimestamp comme entrée à trunc().

Pour vos données d'exemple en utilisant systimestamp ou sysdate ne va rien trouver, donc je vais utiliser un faux temps fixe pour le reste, généré dans un CTE pour la séparation. Où j'ai utilisé now du CTE, vous utiliseriez systimestamp ou sysdate.

La deuxième partie consiste à obtenir la moyenne de chaque nom au cours de cette période. Qui est simple agrégation:

with fake_time(now) as (
    select timestamp '2017-02-10 13:01:07' from dual 
) 
select name, 
    avg(value) as avg_value, 
    cast(trunc(now, 'HH24') as timestamp) as time 
from fake_time 
join table1 on time >= cast(trunc(now, 'HH24') as timestamp) - interval '1' hour 
and time < cast(trunc(now, 'HH24') as timestamp) 
group by name, now; 

NAME  AVG_VALUE TIME     
------- ---------- ----------------------- 
QWER1_Z   20 2017-02-10 13:00:00.000 
QWER1_V   35 2017-02-10 13:00:00.000 
TEST1_Z   15 2017-02-10 13:00:00.000 
TEST1_V   10 2017-02-10 13:00:00.000 

Pour ramasser les lignes que vous voulez que j'ai fait le temps faux 13:00 au lieu de 12:00. La moyenne que vous avez montrée pour TEST1_V était également fausse.

L'étape suivante est de faire pivoter ceux-ci dans le format souhaité, en une seule ligne. Pour cela, vous pouvez ajouter la racine (c.-à-d.TEST1 ou QWER1) et la lettre (Z ou V) sous forme de colonnes supplémentaires dans le jeu de résultats, puis de les utiliser comme sous-requête pour la pivot operation - cela nécessite 11g ou plus:

with fake_time(now) as (
    select timestamp '2017-02-10 13:01:07' from dual 
) 
select z_name, z_value, v_name, v_value, time 
from (
    select substr(name, 1, length(name) - 2) as root, 
    substr(name, -1) as zv, 
    name, 
    avg(value) as avg_value, 
    cast(trunc(now, 'HH24') as timestamp) as time 
    from fake_time 
    join table1 on time >= cast(trunc(now, 'HH24') as timestamp) - interval '1' hour 
    and time < cast(trunc(now, 'HH24') as timestamp) 
    group by substr(name, 1, length(name) - 2), name, now 
) 
pivot (max(name) as name, max(avg_value) as value for (zv) in ('Z' as z, 'V' as v)); 

Z_NAME  Z_VALUE V_NAME  V_VALUE TIME     
------- ---------- ------- ---------- ----------------------- 
TEST1_Z   15 TEST1_V   10 2017-02-10 13:00:00.000 
QWER1_Z   20 QWER1_V   35 2017-02-10 13:00:00.000 

Il peut être une autre étape nécessaire ; Dans votre exemple de sortie, vous avez inclus une liste des valeurs d'origine qui ont été moyennées, mais vous n'avez pas confirmé si vous en vouliez réellement ou si elles montraient simplement comment la moyenne était calculée pour nous aider à comprendre ce que vous deviez faire. Si vous voulez vraiment comprendre que vous pouvez utiliser listagg() et concaténation pour construire la chaîne « moyenne » avant pivotante:

'avg(' || listagg(value, ',') within group (order by value) || ') = ' || avg(value) 
     as avg_value, 

pour obtenir

Z_NAME Z_VALUE    V_NAME V_VALUE    TIME     
------- -------------------- ------- -------------------- ----------------------- 
TEST1_Z avg(10,20) = 15  TEST1_V avg(10) = 10   2017-02-10 13:00:00.000 
QWER1_Z avg(20) = 20   QWER1_V avg(30,40) = 35  2017-02-10 13:00:00.000 

Comme je l'ai dit plus tôt, je n'ai utilisé le fake_date CTE pour obtenir une date qui correspond à vos données d'échantillon. Votre vraie requête sera plus comme:

select z_name, z_value, v_name, v_value, time 
from (
    select substr(name, 1, length(name) - 2) as root, 
    substr(name, -1) as zv, 
    name, 
    avg(value) as avg_value, 
    cast(trunc(sysdate, 'HH24') as timestamp) as time 
    from table1 
    where time >= cast(trunc(sysdate, 'HH24') as timestamp) - interval '1' hour 
    and time < cast(trunc(sysdate, 'HH24') as timestamp) 
    group by substr(name, 1, length(name) - 2), name 
) 
pivot (max(name) as name, max(avg_value) as value for (zv) in ('Z' as z, 'V' as v)); 
+0

merci pour l'explication, mais je ne peux pas faire n'importe quelle session d'alter:/ – 4est

+0

@ 4est - la session de modification est juste pour contrôler comment dates et timestamps affiché par défaut dans mon client, et c'était surtout pour montrer la distinction entre les deux types de données. Vous ne devriez pas compter sur les paramètres NLS de toute façon; pour votre sortie finale (si cela n'est pas consommé par un autre processus), vous devez utiliser 'to_char()' pour formater les valeurs d'horodatage. –

+0

@ alex: que devrait être au lieu de "select timestamp" 2017-02-10 13:01:07 'de dual ", dans ma requête org? – 4est

0
select T1.Z, T1.V from (
(select avg(values) from table1 where name like '%Z' and time between sysdate and sysdate - interval '1' group by INSTR(name,'Z')) Z, 
(select avg(values) from table1 where name like '%V' and time between sysdate and sysdate - interval '1' group by INSTR(name,'V')) V) T1 
+0

J'ai eu l'erreur: ORA-30089: champ manquant ou invalide ........ quand je cours seulement un choix j'ai eu la même erreur – 4est

+0

essaye maintenant s'il vous plaît, j'ai trouvé erreur – starko

+0

peut-être vous devez utiliser la fonction TO_DATE sur la colonne de temps dans la requête: https://www.techonthenet.com/oracle/functions/to_date.php – starko