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;