2017-06-20 2 views
0

J'ai un ensemble de données qui a ID, datetime + tas de champs de valeur.Tous les enregistrements à moins d'une heure les uns des autres

L'idée est que les enregistrements sont à moins d'une heure l'un de l'autre sont une session. Il ne peut y avoir qu'une session toutes les 24 heures. (L'heure est mesurée à partir du début du premier enregistrement)

L'approche de jour() ne fonctionne pas car un enregistrement peut être 23:55 et le suivant pourrait être 00:01 le jour suivant et il serait la même session.

J'ai ajouté rowid et couru les éléments suivants:

data testing; 
set testing; 
by subscriber_no; 
prev_dt = lag(record_ts); 
prev_row = lag(rowid); 
time_from_last = intck("Second",record_ts,prev_dt); 
if intck("Second",record_ts,prev_dt) > -60*60 and intck("Second",record_ts,prev_dt) < 0 then 
    same_session = 'yes'; 
else same_session = 'no'; 
if intck("Second",record_ts,prev_dt) > -60*60 and intck("Second",record_ts,prev_dt) < 0 then 
    rowid = prev_row; 
else rowid = rowid; 
format prev_dt datetime19.; 
output; 
run; 

fichier d'entrée d'entrée

ID record_TS rowid 
52 17MAY2017:06:24:28 4 
52 17MAY2017:07:16:12 5 
91 05APR2017:07:04:55 6 
91 05APR2017:07:23:37 7 
91 05APR2017:08:04:52 8 
91 05MAY2017:08:56:23 9 

est triée par ID et enregistrer TS.

La sortie était

ID record_TS rowid prev_dt prev_row time_from_last same_session  
52 17MAY2017:06:24:28 4 28APR2017:08:51:25 3 -1632783 no 
52 17MAY2017:07:16:12 4 17MAY2017:06:24:28 4 -3104 yes 
91 05APR2017:07:04:55 6 17MAY2017:07:16:12 5 3629477 no 
91 05APR2017:07:23:37 6 05APR2017:07:04:55 6 -1122 yes 
91 05APR2017:08:04:52 7 05APR2017:07:23:37 7 -2475 yes This needs to be 6 
91 05MAY2017:08:56:23 9 05APR2017:08:04:52 8 -2595091 no 

Deuxième rangée du bas - rowid sort 7, alors que je besoin de venir être 6.

Fondamentalement, je dois changer la rowid actuelle enregistrée avant la le script se déplace pour évaluer le suivant.

Merci Ben

J'ai réalisé ce que je avais besoin avec

proc sql; 
    create table testing2 as 
     select distinct t1.*, min(t2.record_TS) format datetime19. as from_time, max(t2.record_TS) format datetime19. as to_time 
     from testing t1 
     join testing t2 on t1.id_val= t2.id_val 
     and intck("Second",t1.record_ts,t2.record_ts) between -3600 and 3600 
    group by t1.id_val, t1.record_ts 
order by t1.id_val, t1.record_ts 
; 

quit; 

Mais je me demande encore s'il y a un moyen de valider les modifications à la ligne courante avant de passer à la prochaine évaluation rangée.

+0

Pourquoi ne pas simplement créer une table "session", ont une ligne par session et défini une date 'ExpiresAt' qui est de 24 heures dans l'avenir. Ensuite, chaque fois qu'un utilisateur fait une demande, mettez 'ExpiresAt' à jour dans 24 heures. – Basic

+0

C'est ce que j'essaie de faire. Je ne peux pas changer la structure de la table source ni les données disponibles. – Ben

+0

Pouvez-vous ajouter vos données HAVE (c'est-à-dire l'ensemble de données en entrée) à la question? La variable subscriber_no est-elle ce qui est imprimé dans la sortie en tant qu'ID? Je remarque que vous avez une instruction BY BY subscriber_no, mais aucune logique pour empêcher deux abonnés différents d'être assignés à la même session. Généralement, c'est une mauvaise idée de faire en sorte que les jeux de données d'entrée et de sortie soient les mêmes, même en testant simplement, car il est difficile de répéter les tests et de vérifier les résultats. – Quentin

Répondre

2

Je pense que votre logique est juste:

  1. datetime Prenez record_TS du premier enregistrement pour chaque ID
  2. Pour les enregistrements suivants, si leur record_TS est à une heure du premier enregistrement de, recoder pour être le même rowID que le premier enregistrement.

Si tel est le cas, vous pouvez utiliser RETAIN pour garder trace du premier enregistrement_TS et de l'identifiant de ligne pour chaque ID. Cela devrait être plus facile que lag(), et permet d'avoir plusieurs enregistrements dans une même session. semble ci-dessous pour travailler:

data have; 
    input ID record_TS datetime. rowid; 
    format record_TS datetime.; 
    cards; 
52 17MAY2017:06:24:28 4 
52 17MAY2017:07:16:12 5 
91 05APR2017:07:04:55 6 
91 05APR2017:07:23:37 7 
91 05APR2017:08:04:52 8 
91 05MAY2017:08:56:23 9 
; 
run; 

data want; 
    set have; 
    by ID Record_TS; 
    retain SessionStart SessionRowID; 
    if first.ID then do; 
    SessionStart=Record_TS; 
    SessionRowID=RowID; 
    end; 
    else if (record_TS-SessionStart)<(60*60) then RowID=SessionRowID; 
    drop SessionStart SessionRowID; 
run; 

Sorties:

ID  record_TS  rowid 

52 17MAY17:06:24:28  4 
52 17MAY17:07:16:12  4 
91 05APR17:07:04:55  6 
91 05APR17:07:23:37  6 
91 05APR17:08:04:52  6 
91 05MAY17:08:56:23  9