condition exist dans le WHERE

condition exist dans le WHERE - SQL/NoSQL - Programmation

Marsh Posté le 11-07-2013 à 13:03:09    

bonjour,
 
je ne sais pas si c'est faisable en sql :
 
dans ma base j'ai un tuple pour ma traduction française, un autre pour l'anglais, un autre pour l'espagnol.
J'aimerai traiter avec une seule requete la condition : "si tu ne trouves pas la langue demandée, tu prends par defaut la langue française"
 
ma table ressemble à ça
id | adresse | langue | menu_parent_id
1 |www.google.fr | français | 45
2 |www.google.com | anglais| 45
3 | | espagnol| 45
 
je ne sais pas si avec  if exists on peut resoudre le probleme?
 
par exemple
select adresse WHERE { if langue espagnole existe je renvoie l'adresse en espagnole sinon je prends le français}
 
sinon je recupere le français et la langue demandés et je fais mon test apres en php...
 
merci!

Reply

Marsh Posté le 11-07-2013 à 13:03:09   

Reply

Marsh Posté le 11-07-2013 à 15:23:57    

Bonjour,
 
Il existe DEFAULT pour ça en SQL.
 
Voici un lien qui peut t'aider  
 
http://www.w3schools.com/sql/sql_default.asp


---------------
Made you your own sentence without believing that of the others...
Reply

Marsh Posté le 11-07-2013 à 19:34:46    

merci je vais zieuter ca!

Reply

Marsh Posté le 12-07-2013 à 17:56:11    

Bonjour,
 
Il existe surement une multitude de manières de résoudre le cas d'école que vous citez. Quelques méthodes me viennent à l'esprit et sont simples à mettre en place.
Tous mes exemples reprennent votre jeu de données dans une clause WITH. Sautez cette partie pour la compréhension.
 
Votre problématique:
Retourner une seule ligne en fonction d'un paramètre. Vous travaillez dans un SGBD relationnel fonctionnant, lors des requêtes SQL simples sur des tuples.
 
Conditions:
Retourner la ligne de la langue recherche si trouvée.
OU
Retourner La ligne par défaut si votre recherche n'aboutie pas
OU
Retourner La ligne par défaut si aucune ligne n'est fournie
 
 
NOTE: Les exemples ont été réalisés sous base Oracle 10.2.0.3. Cependant la syntaxe SQL utilisée est normalement ANSI ou très proche.
 
Méthode 0: Conditions + EXISTS
L'important est de garde et de comprendre toutes les conditions qu'implique votre problématique.
Les conditions appliquées sont:
   - Si la ligne courante est égale à MA_LANGUE
   OU Si la ligne courante est égale à PAR_DEFAUT et qu'il n'existe pas de MA_LANGUE dans la table
   OU SI la ligne courante est égale à PAR_DEFAUT et que MA_LANGUE n'est pas renseignée (overkill)
 
WITH localisation_sites AS (
  SELECT 1 as id ,'www.google.fr' as adresse , 'français' as langue , 45 as menu_parent_id FROM DUAL
  UNION
  SELECT 2 as id , 'www.google.com' as adresse , 'anglais' as langue , 45 as menu_parent_id  FROM DUAL
  UNION
  SELECT 3 as id , NULL as adresse , 'espagnol' as langue , 45 as menu_parent_id FROM DUAL)  
SELECT pe.id
      ,pe.adresse
      ,pe.langue
      ,pe.menu_parent_id
  FROM localisation_sites pe
 WHERE 1 = 1
   AND (pe.langue = :ma_langue OR
       pe.langue = 'français' AND NOT EXISTS
        (SELECT 1
           FROM localisation_sites pe
          WHERE 1 = 1
            AND pe.langue = :ma_langue)
OR
        :ma_langue IS NULL AND pe.langue = 'français')
 
 
Méthode 1: UNION ALL + EXISTS
Le concept est de faire une jointure entre deux requêtes. Une ramenant la ligne de votre langue si celle-ci existe. L'autre de ramener celle de votre valeur par défaut si la valeur que vous souhaitez remonter n'existe pas.
Union ALL est mis pour ne pas faire de DISTINCT inutile entre les lignes.
Le cas du null est géré implicitement par le second UNION.
 
 
WITH localisation_sites AS (
  SELECT 1 as id ,'www.google.fr' as adresse , 'français' as langue , 45 as menu_parent_id FROM DUAL
  UNION
  SELECT 2 as id , 'www.google.com' as adresse , 'anglais' as langue , 45 as menu_parent_id  FROM DUAL
  UNION
  SELECT 3 as id , NULL as adresse , 'espagnol' as langue , 45 as menu_parent_id FROM DUAL)  
SELECT pe.id, pe.adresse, pe.langue, pe.menu_parent_id
  FROM localisation_sites pe
 WHERE 1 = 1
   AND pe.langue = :ma_langue
UNION ALL
SELECT pe2.id, pe2.adresse, pe2.langue, pe2.menu_parent_id
  FROM localisation_sites pe2
 WHERE 1 = 1
   AND pe2.langue = 'français'
   AND NOT EXISTS (SELECT 1
          FROM localisation_sites pe
         WHERE 1 = 1
           AND pe.langue = :ma_langue);
 
 
Méthode 2: Jointure Externe
Une autre manière pourrait être l'auto-jointure externe à gauche. La méthode sera surement plus consommatrice en ressources sur des tables mal indexées.
Le principe est de ramener toujours votre ligne par défaut 'français' par exemple et de faire une auto-jointure à gauche afin de ramener, si elle existe la ligne de votre langue.
Le résultat sera un seul et même tuple avec les informations des deux tables, le défaut et si elles existent celle de la langue souhaitée.
Il ne vous reste ensuite qu'à prendre les bonnes valeurs :
   

  • Les valeurs par défaut si le champ de la clé de votre source est vide

 

  • Les valeurs de la langue souhaitée sinon


/** Table de données semblable à l'exemple */        
WITH localisation_sites AS (
  SELECT 1 as id ,'www.google.fr' as adresse , 'français' as langue , 45 as menu_parent_id FROM DUAL
  UNION
  SELECT 2 as id , 'www.google.com' as adresse , 'anglais' as langue , 45 as menu_parent_id  FROM DUAL
  UNION
  SELECT 3 as id , NULL as adresse , 'espagnol' as langue , 45 as menu_parent_id FROM DUAL)    
SELECT CASE
          WHEN pe.id IS NULL THEN
           pe_def.id
          ELSE
           pe.id
       END AS id
      ,CASE
          WHEN pe.id IS NULL THEN
           pe_def.adresse
          ELSE
           pe.adresse
       END AS adresse
      ,CASE
          WHEN pe.id IS NULL THEN
           pe_def.langue
          ELSE
           pe.langue
       END AS langue
      ,CASE
          WHEN pe.id IS NULL THEN
           pe_def.menu_parent_id
          ELSE
           pe.menu_parent_id
       END AS menu_parent_id
  FROM localisation_sites pe_def
  LEFT OUTER JOIN localisation_sites pe
    ON (1 = 1)
 WHERE 1 = 1
   AND pe_def.langue = 'français'
   AND pe.langue = nvl(:ma_langue, pe_def.langue) -- Pour gérer le cas d'une langue NULL ... overkill
 
Bonne étude de cas. Ne vous contentez pas de prendre au hasard, prenez le temps de comprendre les cas :]
Ces deux exemples ne sont que deux possibilités. En m'amusant avec la résolution de ce cas j'ai réalisé 5 autres méthodes de récupération des données. Toutes plus farfelues les unes que les autres certes mais toutes aboutissent.
 
Cordialement !


Message édité par zyniel le 12-07-2013 à 18:23:28
Reply

Marsh Posté le 12-07-2013 à 18:52:13    

merci.
y a-t-il une raison pour avoir dans la methode 1 "WHERE 1 = 1 ", je ne comprends pas son utilité?

Reply

Marsh Posté le 12-07-2013 à 22:09:36    

Le WHERE 1 = 1 me sert pour commenter plus rapidement la première des conditions dans une requête SELECT dans le cas d'opérateurs AND/OR en début de ligne.  
Sachant qu'il s'agit d'une condition toujours vraie et sans impact sur la requête (pas de champs mis en jeu) et ses performances.
 
WHERE condition_1
AND condition_2
AND condition_3
 
soit se commenter en
 
WHERE /* condition_1
AND */ condition_2
AND condition_3
 
Alors qu'avec le 1 = 1 ... :
WHERE 1 = 1
-- AND condition_1
AND condition_2
AND condition_3


Message édité par zyniel le 12-07-2013 à 22:15:17
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed