condition exist dans le WHERE - SQL/NoSQL - Programmation
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
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 :
/** 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 !
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é?
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
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!