J'essaie de créer un tableau qui ne renseigne les entrées d'un contact d'un client à un numéro d'entreprise que s'il n'a PAS été contacté pour la première fois à un numéro de domicile dans les 24 heures précédant la tentative d'attribution du numéro d'entreprise.
Donc si j'ai
1 20MAY2018:06:24:28 B 2 24MAY2018:06:24:28 B 5 29MAY2018:07:24:28 B 5 29MAY2018:08:24:28 B
Je veux pouvoir obtenir
DATA HAVE; INPUT ID RECORD DATETIME. TYPE; FORMAT RECORD DATETIME.; CARDS; 1 17MAY2018:06:24:28 H 1 18MAY2018:05:24:28 B 1 20MAY2018:06:24:28 B 2 20MAY2018:07:24:28 H 2 20MAY2018:08:24:28 B 2 22MAY2018:06:24:28 H 2 24MAY2018:06:24:28 B 3 25MAY2018:06:24:28 H 3 25MAY2018:07:24:28 B 3 25MAY2018:08:24:28 B 4 26MAY2018:06:24:28 H 4 26MAY2018:07:24:28 B 4 27MAY2018:08:24:28 H 4 27MAY2018:09:24:28 B 5 28MAY2018:06:24:28 H 5 29MAY2018:07:24:28 B 5 29MAY2018:08:24:28 B ; RUN;
J'ai essayé d'ajouter un décompte à l'ID mais Je ne sais pas comment j'utiliserais cela, ou s'il existe un moyen d'utiliser une sous-requête dans un proc sql pour créer un nombre d'observations qui en ont plus d'une sur une période de 24 heures.
p>
4 Réponses :
Je crois que j'ai compris!
J'ai des tables HAVEA et HAVEB hébergeant respectivement des entrées de type H et de type B.
Ensuite, j'ai exécuté les PROC SQL suivants.
PROC SQL; CREATE TABLE WANTA AS SELECT A.RECORD AS PREVIOUS_CALL, B.* FROM HAVEB B JOIN HAVEA A ON (B.ID=A.ID AND A.RECORD LE B.RECORD); CREATE TABLE WANTB AS SELECT * FROM WANTA GROUP BY ID, RECORD HAVING PREVIOUS_CALL = MAX(PREVIOUS_CALL); CREATE TABLE WANTC AS SELECT * FROM WANTB WHERE INTNX('HOUR',RECORD,-24,'SAME') GT PREVIOUS_CALL; QUIT;
S'il vous plaît laissez-moi savoir si ce n'est pas une réponse durable pour de plus grandes quantités de données ou s'il existe une bien meilleure méthode pour aborder cela.
Donc, votre approche fonctionnera, mais sera assez désordonnée avec de grands nombres - comme vous faites une jointure cartésienne dans ID. Si chaque ID a peu d'enregistrements, ce n'est pas si mal, mais si chaque ID contient de nombreux enregistrements, vous établissez beaucoup de connexions.
Heureusement, il existe un moyen simple de le faire dans SAS!
data want; do _n_ = 1 by 1 until (last.id); *for each ID:; set have; by id; if first.id then last_home=0; *initialize last_home to 0; if type='H' then last_home = record; *if it is a home then save it aside; if type='B' and intck('Hour',last_home,record,'c') gt 24 then output; *if it is business then check if 24 hours have passed; end; format last_home datetime.; run;
Ce sera beaucoup plus rapide que SQL sur des ensembles de données plus volumineux, si pour aucune autre raison que cela ne passe les données qu'une seule fois. SQL le fera nécessairement plusieurs fois, même si vous ne séparez pas HAVEA / HAVEB et faites cela dans la requête SQL.
C'est tellement ennuyeux, maintenant que je le vois, c'est parfaitement logique, mais je ne pourrais pas pour la vie de moi le trouver moi-même. Avec cette étape de données, les principaux besoins avant cela sont de s'assurer que les données sont dans une seule table et triées par ID puis par enregistrement, n'est-ce pas?
Droite. Et vous pouvez appliquer le RECORD en l'ajoutant à l'instruction BY sans problème réel. Il n'est pas nécessaire qu'il soit dans un seul ensemble de données, vous pouvez faire quelque chose de similaire s'il est en deux (soit HAVEA et HAVEB, avec une MERGE, soit plusieurs ensembles de données s'étendant sur plusieurs jours, simplement en les ajoutant à l'instruction SET).
Vous effectuez une sélection pour obtenir le jeu de résultats final sans créer de tableaux intermédiaires. Voici deux alternatives:
Première manière
Semblable à votre «comprendre». Une jointure réflexive avec regroupement détecte les appels «to_home» avant les appels «to_business» qui ne se sont PAS produits au cours des dernières 24 heures (86 400 secondes)
create table want2 as select business.* from have as business where business.type = 'B' and not exists ( select * from have as home where home.id = business.id and home.type = 'H' and home.call_dt < business.call_dt and home.call_dt >= business.call_dt - 86400 ) ;
Second manière
Effectuez une vérification NON existentielle, pour un appel to_home dans les 24 heures précédentes, pour chaque appel to_business.
proc sql; create table want as select distinct business.* from have as business join have as home on business.id = home.id & business.type = 'B' & home.type = 'H' & home.CALL_DT < business.CALL_DT group by business.call_dt having max(home.call_dt) < business.call_dt - 86400 ;
Une solution HASH a quelques dépendances (quantité de données et RAM) ... mais c'est une autre alternative
DATA HAVE; INPUT ID RECORD DATETIME. TYPE $; FORMAT RECORD DATETIME.; CARDS; 1 17MAY2018:06:24:28 H 1 18MAY2018:05:24:28 B 1 20MAY2018:06:24:28 B 2 20MAY2018:07:24:28 H 2 20MAY2018:08:24:28 B 2 22MAY2018:06:24:28 H 2 24MAY2018:06:24:28 B 3 25MAY2018:06:24:28 H 3 25MAY2018:07:24:28 B 3 25MAY2018:08:24:28 B 4 26MAY2018:06:24:28 H 4 26MAY2018:07:24:28 B 4 27MAY2018:08:24:28 H 4 27MAY2018:09:24:28 B 5 28MAY2018:06:24:28 H 5 29MAY2018:07:24:28 B 5 29MAY2018:08:24:28 B ; RUN; /* Keep only HOME TYPE records and rename RECORD for using in comparision */ Data HOME(Keep=ID RECORD rename=(record=hrecord)); Set HAVE(where=(Type="H")); Run; Data WANT(Keep=ID RECORD TYPE); /* Use only BUSINESS TYPE records */ Set HAVE(where=(Type="B")); /* Set up HASH object */ If _N_=1 Then Do; /* Multidata:YES for looping through all successful FINDs */ Declare HASH HOME(dataset:"HOME", multidata:'yes'); home.DEFINEKEY('id'); home.DEFINEDATA('hrecord'); home.DEFINEDONE(); /* To prevent warnings in the log */ Call Missing(HRECORD); End; /* FIND first KEY match */ rc=home.FIND(); /* Successful FINDs result in RC=0 */ Do While (RC=0); /* This will keep the result of the most recent, in datetime, HOME/BUS record comparision */ If intck('Hour',hrecord,record,'c') > 24 Then Good_For_Output=1; Else Good_For_Output=0; /* Keep comparing HOME/BUS for all HOME records */ rc=home.FIND_NEXT(); End; If Good_For_Output=1 Then Output; Run;