Précédent   Forum des professionnels en informatique > Logiciels > Solutions d'entreprise > Business Intelligence > SAS > SAS Base
SAS Base Forum d'entraide sur SAS base : étape data, procédures non statistiques, procédures non graphiques, SQL
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 06/04/2011, 19h12   #1
Invité régulier
 
Inscription : août 2008
Messages : 32
Détails du profil
Informations forums :
Inscription : août 2008
Messages : 32
Points : 6
Points : 6
Par défaut Proc SQL (Dernière enregistrement)

Bonjour,

Je cherche à écrire une requête SQL en SAS pour pouvoir écrire dans ma table TEST2 uniquement
un enregistrement par NOM avec le NUMERO le plus élevé et le MONTANT le plus gros.

Dans mon exemple ci-dessous, le résultat de ma requêtre SQL me donne 2 enregistrements,

par contre je désire avoir seulement le résultat suivant : Éric 6 200

À noté que cela est un exemple, s.v.p. ne pas répondre à ma
question avec : where = (NOM = 'Éric' and NUMERO = '6' and MT = 200) car pour vrai, j'extrait 1 million de données.

En résumé, j'essaye d'effectuer un genre de last.output = avoir le dernier
enregistrement d'une requêtre selon un tri.

Selon plusieurs personnes, ca semble être impossible à réaliser, par contre,
ça semble être du SQL de base.

Pouvez-vous m'aider s.v.p. ?

Merci et bonne journée.

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
DATA TEST;                                                                                    
  INPUT NOM$1-5 NUMERO$6 MONTANT;                                                             
  cards;                                                                                      
  Éric 6 200                                                                                  
  Éric 6 100                                                                                  
  Éric 2 300                                                                                  
  Éric 2 400                                                                                  
  ;                                                                                           
run;                                                                                          
 
 
 
proc sql;                                                                                     
CREATE TABLE TEST2 AS SELECT *                                                                
FROM TEST                                                                                     
 
WHERE                                                                                         
     NUMERO = SELECT DISTINCT (MAX(NUMERO)) FROM TEST                                         
     ORDER BY NUMERO,NOM,MT;                                                                  
QUIT;                                                                                         
 
 
proc print DATA=TEST2;                                                                        
run;

Résultat avec cette requêtre :


Obs NOM NUMERO MT

1 Éric 6 100
2 Éric 6 200
SAS_ERIC est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 06/04/2011, 19h26   #2
Membre Expert
 
Avatar de MEGAMIND2
 
Homme Brice Beare
Paris
Inscription : janvier 2011
Messages : 956
Détails du profil
Informations personnelles :
Nom : Homme Brice Beare
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Paris

Informations forums :
Inscription : janvier 2011
Messages : 956
Points : 1 366
Points : 1 366
Je crois qu'il faut générer une table par personne puis concatener toutes les tables.

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
DATA TEST;
INPUT NOM$1-5 NUMERO  MONTANT;
cards;
Éric 6 200
Éric 6 100
Éric 2 300
Éric 2 400
;
run;
 
proc sql;
CREATE TABLE TEST2 AS SELECT *
FROM TEST
WHERE
NUMERO = SELECT DISTINCT (MAX(NUMERO)) FROM TEST
ORDER BY NUMERO,NOM,MONTANT;
QUIT;
 
PROC SQL;
CREATE TABLE TEST3 AS SELECT DISTINCT NOM,NUMERO,MAX(MONTANT) AS MONTANT
FROM TEST2 ORDER BY NUMERO,NOM,MONTANT;
QUIT;
MEGAMIND2 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 06/04/2011, 19h38   #3
Invité régulier
 
Inscription : août 2008
Messages : 32
Détails du profil
Informations forums :
Inscription : août 2008
Messages : 32
Points : 6
Points : 6
Par défaut Réponse

Merci pour la réponse, par contre je veux vraiment avoir seulement une requête SQL avec tes 2 proc sql
SAS_ERIC est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 07/04/2011, 07h45   #4
Expert Confirmé
 
Avatar de olivier.decourt
 
Homme Olivier Decourt
Formateur en informatique
Inscription : avril 2008
Messages : 1 467
Détails du profil
Informations personnelles :
Nom : Homme Olivier Decourt
Âge : 34
Localisation : France

Informations professionnelles :
Activité : Formateur en informatique
Secteur : Conseil

Informations forums :
Inscription : avril 2008
Messages : 1 467
Points : 2 823
Points : 2 823
Bonjour Eric.
En SQL, il n'y a pas forcément de solution basique. Mais j'ai quand même 2 solutions à te proposer.
La 1e ne fonctionnera qu'en SQL SAS (donc pas de pass-thru, et si tes millions de lignes sont sur une base de données externe, attends-toi à un temps de traitement... un peu long) car on fusionne des stats et des données de détail dans la même requête. L'idée étant de procéder en deux temps : pour chaque nom et numéro, récupérer la ligne correspondant à un maximum de montant ; puis se servir de ce résultat en requête imbriquée (ou en passant par une table intermédiaire si tu manques de mémoire vive pour les requêtes imbriquées) pour récupérer la ligne avec le plus grand numéro.
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
PROC SQL ;
SELECT DISTINCT nom, numero, montant, MAX(numero) AS numMax
FROM
(
  SELECT DISTINCT *, MAX(montant) AS mtMax
  FROM test
  GROUP BY nom, numero
  HAVING montant=mtMax
)
GROUP BY nom
HAVING numero = numMax
  ;
QUIT ;
Sinon, la solution en SQL "standard" est de passer par des requêtes imbriquées corrélées, un immondice logique particulièrement marécageux à mes yeux : c'est une requête imbriquée qui n'est pas indépendante de la requête mère car elle partage des infos avec elle. Attention ça tache :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
proc sql;                                                                                     
SELECT *                                                                
FROM TEST AS t1                                                                                    
 
WHERE                                                                                         
     montant = (SELECT MAX(montant) 
			    FROM TEST AS t2 
			    WHERE t1.nom=t2.nom
                 AND numero=(SELECT MAX(numero)
				 			  FROM TEST AS t3
							  WHERE t3.nom=t1.nom)
               )                                         
     ORDER BY NUMERO,NOM,MONTANT ;                                                                  
QUIT;
L'avantage c'est qu'en pass-thru ou en Libname vers un SGBD celui-ci devrait pouvoir exécuter la requête tout seul.

S'il n'y a pas de solution plus simple, c'est parce qu'une étape Data lit linéairement une table SAS (de la 1e à la dernière observation, en un seul passage), alors que les requêtes SQL font des passages successifs sur le fichier et donc on ne peut pas utiliser l'ordre des observations. Tu auras le même souci le jour où tu voudras faire l'équivalent d'un LAG ou d'un RETAIN en SQL : ce genre de notions n'est pas intégrée au langage à cause de son mode d'exécution.

Bon courage et tiens-nous au courant.
Olivier
olivier.decourt est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 05h42.


 
 
 
 
Partenaires

Hébergement Web