Calculer la différence de time pour les lignes consécutives

Quelqu'un peut-il m'aider avec une requête SQL selon mon exigence ci-dessous? J'ai une table comme ça.

S_ID S_ACTV_CODE S_USER S_DATETIME S_ACT_IND AAA-111 NULL USER1 2015-06-15 00:21:06 0 AAA-111 2 USER1 2015-06-15 00:21:07 0 AAA-111 2 USER1 2015-06-15 00:25:12 0 AAA-111 4 USER2 2015-06-17 03:20:33 0 AAA-111 3 USER1 2015-06-17 03:43:25 0 AAA-111 4 USER3 2015-06-22 05:02:37 0 AAA-111 4 USER4 2015-06-23 05:25:05 1 AAA-112 NULL USER4 2015-06-25 11:11:11 0 AAA-112 4 USER3 2015-06-25 11:11:12 0 AAA-112 4 USER4 2015-06-26 20:25:49 0 AAA-112 4 USER2 2015-06-29 18:04:32 1 AAA-113 NULL USER2 2015-06-24 07:10:37 0 AAA-113 NULL USER1 2015-06-24 07:10:41 0 AAA-113 3 USER1 2015-06-24 07:10:43 1 

Fondamentalement, je veux calculer le time passé par S_Users sur un S_ACTV_CODE particulier:

  • S_ACTV_CODE_PREV signifie les loggings actifs précédents.
  • S_START_TIME est l'heure de S_DATETIME lors du démarrage d'un S_ACTV_CODE
  • S_END_TIME est le timeout avant qu'un S_ACTV_CODE ne soit remplacé par un autre S_ACTV_CODE
  • Pour le premier logging, S_ACTV_CODE est nul, donc il n'y a pas de S_ACTV_CODE_PREV, donc S_ACTV_CODE_PREV est NULL
  • Pour le deuxième logging S_ACTV_CODE a une certaine valeur, mais S_ACTV_CODE_PREV est NULL pour le premier logging. Donc, le deuxième logging S_ACTV_CODE_PREV est également NULL
  • Pour le dernier logging (signifie S_ACTV_IND = 1), l'user travaille actuellement dessus et S_ACTV_CODE n'est pas modifié. Donc S_END_TIME est un time ouvert et nous voulons le garder comme NULL

Donc, le résultat devrait être comme ci-dessous:

 S_ID S_ACTV_CODE_PREV S_ACTV_CODE_CURR S_USER S_START_TIME S_END_TIME TIME_SPENT (in Sec) AAA-111 NULL NULL USER1 2015-06-15 00:21:06 2015-06-15 00:21:07 1 AAA-111 NULL 2 USER1 2015-06-15 00:21:07 2015-06-17 03:20:33 183566 AAA-111 2 4 USER2 2015-06-17 03:20:33 2015-06-17 03:43:25 1372 AAA-111 4 3 USER3 2015-06-17 03:43:25 2015-06-22 05:02:37 436752 AAA-111 3 4 USER4 2015-06-22 05:02:37 NULL NULL AAA-112 NULL NULL USER4 2015-06-25 11:11:11 2015-06-25 11:11:12 1 AAA-112 NULL 4 USER3 2015-06-25 11:11:12 NULL NULL AAA-113 NULL NULL USER2 2015-06-24 07:10:37 2015-06-24 07:10:43 6 AAA-113 NULL 3 USER1 2015-06-24 07:10:43 NULL NULL 

Re-écrit le SQL pour get la première date et le dernier user pour les lignes. Cela l'a rendu bien plus moche, mais cela devrait fonctionner:

 select s_id, lag(s_actv_code, 1) over (partition by s_id order by s_datetime asc) as s_actv_code_prev, s_actv_code, s_user, s_datetime as start_time, lead(s_datetime, 1) over (partition by s_id order by s_datetime asc) as end_time, datediff (second, s_datetime, lead(s_datetime, 1) over (partition by s_id order by s_datetime asc)) as duration from ( select distinct s_id, S_ACTV_CODE, last_value(s_user) over (partition by s_id, S_ACTV_CODE, GRP order by S_datetime asc rows between current row and unbounded following) as s_user, first_value(s_datetime) over (partition by s_id, S_ACTV_CODE, GRP order by S_datetime asc ROWS UNBOUNDED PRECEDING ) as s_datetime from ( select *, row_number() over (partition by s_id order by s_datetime asc) - row_number() over (partition by s_id, s_actv_code order by s_datetime asc) as GRP from table1 ) X ) Y order by s_id, start_time 

Edit: Ajout de la partition par s_id en raison de nouveaux changements dans l'exemple.

Vous pouvez tester cela dans SQL Fiddle

merci pour vos réponses. J'ai mis à jour la requête ci-dessous.

 SELECT S_ID, LAG(S_ACTV_CODE, 1) OVER (PARTITION BY S_ID ORDER BY S_DATETIME ASC) AS S_ACTV_CODE_PREV, S_ACTV_CODE, S_USER, S_DATETIME AS START_TIME, LEAD(S_DATETIME, 1) OVER (PARTITION BY S_ID ORDER BY S_DATETIME ASC) AS END_TIME, DATEDIFF (SECOND, S_DATETIME, LEAD(S_DATETIME, 1) OVER (PARTITION BY S_ID ORDER BY S_DATETIME ASC)) AS DURATION FROM ( SELECT S_ID, LAG(S_ACTV_CODE, 1, 'N/A') OVER (PARTITION BY S_ID ORDER BY S_DATETIME ASC) AS S_ACTV_CODE_PREV, S_ACTV_CODE, S_USER, S_DATETIME FROM TABLE1 ) X WHERE ISNULL(S_ACTV_CODE_PREV,'') != ISNULL(S_ACTV_CODE,'') ORDER BY S_ID, START_TIME; 

La requête ci-dessus a fonctionné pour moi et a donné les résultats attendus. Merci encore pour toutes vos réponses.