Fedsql

SAS et SQL : Comment répliquer OVER PARTITION BY dans SAS

Simon 10 vues
Niveau de difficulté
Débutant
Publié le :
Simon

Le mot de l'Expert

Par Simon

Ne voyez pas l'absence de PARTITION BY dans PROC SQL comme une lacune, mais comme une opportunité de performance. L'étape DATA avec le traitement par groupe (BY) est souvent bien plus rapide que les Window Functions SQL : en exploitant la logique séquentielle (FIRST., RETAIN), vous traitez vos données complexes en une seule passe mémoire, là où le moteur SQL multiplierait les lectures.

Pour les analystes de données venant du monde SQL standard (Oracle, SQL Server, PostgreSQL), l'une des premières frustrations dans SAS© est l'absence apparente de support pour les fonctions de fenêtrage (Window Functions).

Des syntaxes courantes comme ROW_NUMBER() OVER (PARTITION BY id ORDER BY date) ou SUM(val) OVER (PARTITION BY group) provoquent des erreurs de syntaxe immédiates dans la PROC SQL de SAS©.

Cet article explique pourquoi cette limitation existe et, surtout, comment la contourner efficacement en utilisant la puissance native du langage SAS©.

Le constat : PROC SQL et la norme ANSI

La procédure standard PROC SQL de SAS© est basée sur une version ancienne de la norme ANSI (principalement ANSI 92). Les fonctions de fenêtrage (introduites plus tardivement dans la norme SQL:2003) ne sont pas supportées par le moteur SQL natif de SAS© Base.

Il est inutile de chercher une option cachée : PROC SQL ne comprendra pas la clause OVER. Cependant, SAS© offre plusieurs alternatives souvent plus performantes pour obtenir le même résultat.

Alternative 1 : L'approche native SAS© (DATA Step)

C'est la méthode la plus "SAS©". Au lieu de penser en termes de requêtes ensemblistes, on utilise le traitement séquentiel du DATA Step combiné à des groupes (BY groups). C'est l'équivalent direct du PARTITION BY.

La logique de correspondance

  • SQL : PARTITION BY variable

  • SAS© : BY variable (nécessite un tri préalable)

  • SQL : ORDER BY date

  • SAS© : PROC SORT par date

Exemple : Répliquer un ROW_NUMBER()

Imaginons que nous voulons numéroter des lignes pour chaque client, triées par date.

En SQL standard :

1SELECT customer_id,
2ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY trans_date) as row_num
3FROM transactions;
4 

En SAS© (DATA Step) : Cette méthode utilise les variables automatiques FIRST. pour détecter le changement de groupe.

1/* 1. Le tri est obligatoire pour utiliser BY */
2PROC SORT DATA=transactions;
3 BY customer_id trans_date;
4RUN;
5 
6/* 2. Le Data Step */
7DATA want;
8 SET transactions;
9 BY customer_id;
10
11 /* Si c'est la première ligne du client, on remet le compteur à 1 */
12 IF first.customer_id THEN row_num = 1;
13 /* Sinon, on incrémente */
14 ELSE row_num + 1;
15RUN;

Exemple : Répliquer un Cumulative SUM

En SQL standard : SUM(amount) OVER (PARTITION BY customer_id ORDER BY date)

En SAS© (DATA Step) :

1DATA want;
2 SET transactions;
3 BY customer_id;
4
5 /* RETAIN garde la valeur de la ligne précédente */
6 retain running_total;
7
8 IF first.customer_id THEN running_total = amount;
9 ELSE running_total = running_total + amount;
10RUN;

Alternative 2 : Le SQL Pass-Through (Délégation)

Si vos données résident déjà dans une base de données puissante (Oracle, SQL Server, Teradata) et que vous utilisez SAS©/ACCESS, il est souvent plus efficace de laisser la base de données faire le travail.

Cette technique, appelée Explicit Pass-Through, envoie votre code SQL natif directement au serveur de base de données. SAS© ne l'interprète pas, il ne fait que recevoir le résultat.

1PROC SQL;
2 connect to oracle (user=... pass=... path=...);
3
4 create TABLE want as
5 select * from connection to oracle
6 (
7 /* Ici, vous pouvez utiliser toute la syntaxe Oracle,
8 y compris les fonctions de fenêtrage */
9 SELECT
10 customer_id,
11 trans_date,
12 RANK() OVER (PARTITION BY customer_id ORDER BY trans_date DESC) as rang
13 FROM
14 schema.transactions
15 );
16
17 disconnect from oracle;
18QUIT;
Avantage : Vous utilisez la syntaxe SQL que vous connaissez déjà et profitez de la puissance du serveur SGBD.

Alternative 3 : Les Procédures Spécifiques

Pour certaines fonctions de fenêtrage courantes comme RANK ou les déciles (NTILE), SAS© dispose de procédures dédiées optimisées qui évitent d'écrire du code complexe.

Pour remplacer RANK() OVER (PARTITION BY ...) :

1PROC RANK DATA=transactions out=want descending;
2 BY customer_id; /* Équivalent du PARTITION BY */
3 var amount; /* La variable sur laquelle on classe */
4 ranks my_rank; /* Le nom de la nouvelle colonne */
5RUN;

Quid de PROC FEDSQL ?

SAS© a introduit une procédure plus moderne appelée PROC FEDSQL, qui vise une conformité ANSI SQL plus stricte (SQL:1999 et au-delà). Bien que FedSQL soit beaucoup plus avancé que PROC SQL, le support complet des fonctions de fenêtrage dépend fortement de l'environnement (SAS© 9 vs SAS© Viya/CAS) et reste parfois limité par rapport aux bases de données natives. Il est recommandé de vérifier la documentation spécifique à votre version de SAS©, mais pour des besoins de fenêtrage classiques, le Data Step reste souvent la voie royale en termes de performance locale.

Besoin SQLSolution SAS© Recommandée
Données locales (SAS© datasets)Utilisez le DATA Step avec BY, FIRST., LAST. et RETAIN. C'est rapide et flexible.
Données dans une DB (Oracle, etc.)Utilisez le SQL Pass-Through (CONNECT TO) pour exécuter le SQL natif.
Calcul de Rangs / PercentilesUtilisez PROC RANK ou PROC UNIVARIATE.
Requêtes simplesRestez sur PROC SQL standard (sans window functions).