2009-05-29 12 views
8

Existe-t-il un moyen d'obtenir les lignes distinctes insensibles à la casse de cette requête SQL SAS? ...Est-il possible de faire un DISTINCT insensible à la casse avec SAS (PROC SQL)?

SELECT DISTINCT country FROM companies; 

La solution idéale consisterait en une seule requête.

Les résultats ressemblent maintenant:

Australia 
australia 
AUSTRALIA 
Hong Kong 
HONG KONG 

... où l'un des 2 lignes distinctes est vraiment nécessaire

On pourrait en majuscules les données, mais cela change inutilement les valeurs d'une manière ne correspond pas à l'objectif de cette requête.

Répondre

6

Si vous avez une clé int primaire (appelons-le ID), vous pouvez utiliser:

SELECT country FROM companies 
WHERE id = 
(
    SELECT Min(id) FROM companies 
    GROUP BY Upper(country) 
) 
+0

Merci. Je pense que c'est la meilleure approche disponible. J'imagine aussi qu'il sera difficile de mettre à l'échelle plusieurs colonnes distinctes et des milliers de lignes, mais cela donnera un coup de feu. Ma requête de la vie réelle est un peu plus élaborée que l'exemple utilisé pour ma question. – Rog

+0

Il doit y avoir une certaine heuristique dans la solution, et je crois que vous devez vous décider explicitement vous-même (par exemple choisir celui avec l'ID le plus bas). Si votre problème SQL est "plus grand" - posez une question plus élaborée et laissez la foule SO essayer ... :) –

+0

Pouvez-vous expliquer dans votre question pourquoi la solution upper() est moins qu'optimale? Dans cette solution, le cas (correct, supérieur, inférieur, fou, etc.) est complètement arbitraire et basé sur l'ordre dans les données. Pourquoi la première instance de cas serait-elle plus pertinente en tant que résultat de retour que l'instance de cas supérieure (pays)? –

2

Normaliser le cas semble souhaitable - si «Australie», «Australie» et «AUSTRALIE» se produisent tous, lequel des trois voudriez-vous que la réponse «cas sensible» unique à votre requête, après tout? Si vous êtes intéressé par certaines heuristiques spécifiques (par exemple, comptez le nombre de fois où elles se produisent et choisissez le plus populaire), cela peut sûrement être fait, mais cela pourrait être une énorme quantité de travail supplémentaire - alors, combien vaut-il pour vous? ?

+0

L'intention est d'utiliser une requête plus compliquée pour montrer les adresses à un utilisateur, et peu importe laquelle est affichée, tant qu'il n'y a pas beaucoup de doublons par cas. – Rog

2

Une méthode non-SQL (vraiment une seule étape que l'étape de données crée juste une vue) serait être:


data companies_v /view=companies_v; 
    set companies (keep=country); 
    _upcase_country = upcase(country); 
run; 

proc sort data=companies_v out=companies_distinct_countries (drop=_upcase_country) nodupkey noequals; 
    by _upcase_country; 
run; 
-2

Je pense que les expressions régulières peuvent vous aider avec le modèle que vous voulez avoir dans votre chaîne de recherche.

Pour l'expression régulière, vous pouvez définir un UDF qui peut être préparé en consultant le didacticiel. www.sqlteam.com/article/expressions-régulières-en-t-sql

Merci.

1

Peut-être que je manque quelque chose, mais pourquoi pas seulement:

data testZ; 
    input Name $; 
    cards4; 
Bob 
Zach 
Tim 
Eric 
Frank 
ZacH 
BoB 
eric 
;;;; 
run; 

proc sql; 
    create view distinctNames as 
    select distinct Upper(Name) from testz; 
quit; 

Cela crée une vue avec seulement des noms distincts comme des valeurs de ligne.

+0

Cela modifie inutilement les valeurs d'une manière qui ne correspond pas à l'objectif de cette requête. En d'autres termes, si une version de cas inférieure (ou appropriée) non dupliquée existe, c'est ce qui devrait apparaître dans les résultats. – Rog

0

Je pensais dans le même sens que Zach, mais je pensais que je regardais le problème avec un exemple plus complexe,

proc sql; 
    CREATE TABLE contacts (
     line1 CHAR(30), line2 CHAR(30), pcode CHAR(4) 
    ); 
    * Different versions of the same address - L23 Bass Plaza 2199; 
    INSERT INTO contacts values('LEVEL 23 bass', 'plaza' '2199'); 
    INSERT INTO contacts values('level 23 bass ', ' PLAZA' '2199'); 

    INSERT INTO contacts values('Level 23', 'bass plaza' '2199'); 
    INSERT INTO contacts values('level 23', 'BASS plaza' '2199'); 

    *full address in line 1; 
    INSERT INTO contacts values('Level 23 bass plaza', '' '2199'); 
    INSERT INTO contacts values(' Level 23 BASS plaza ', '' '2199'); 

;quit; 

Maintenant, nous pouvons sortie
i. Un de chaque catégorie? C'est à dire trois adresses?
OU
ii. Ou juste une adresse? si oui, quelle version devrions-nous préférer?

La mise en œuvre cas 1 peut être aussi simple que:

proc sql; 
    SELECT DISTINCT UPCASE(trim(line1)), UPCASE(trim(line2)), pcode 
    FROM contacts 
;quit; 

La mise en œuvre de cas 2 peut être aussi simple que:

proc sql; 
    SELECT DISTINCT UPCASE(trim(line1) || ' ' || trim(line2)) , pcode 
    FROM contacts 
;quit; 
+0

Dans le second cas, nous pourrions utiliser un * caractère spécial * pour délimiter les colonnes afin de pouvoir les séparer plus tard. c'est à dire. SELECT DISTINCT UPCASE (trim (ligne1) || '$$' || trim (ligne2)) Adresse AS, pcode FROM contacts ; Donc, si nous pouvons marquer l'adresse de retour à line1 et line2 si nécessaire .. Juste un si je suis sûr qu'il y a de meilleures façons de le faire .. :) – Raz

+0

Nous voudrions le cas 2 (1 adresse), mais idéalement le Le résultat doit être l'une des adresses existantes et non une nouvelle version majuscule. – Rog

0

De SAS 9:

données tri proc = input_ds sortseq = linguistique (strengh = primary);

by sort_vars; 

run;