2009-09-01 7 views
0

Say Employé a trois colonnes Prénom, Nom et ID.façon plus rapide de faire cette requête de sélection

La requête doit d'abord rechercher un nom dans le prénom, uniquement s'il est introuvable rechercher le nom de famille.

sélectionnez * de Employé où Prénom = 'test%' ou nom = 'test'% '. ne va pas travailler.

La requête ci-dessous fonctionnera.

select FirstName, LastName, ID 
from EMPLOYEE 
WHERE 
    LastName = 'Test%' 
    AND 
    (COUNT(SELECT FirstName, LastName, ID FROM EMPLOYEE WHERE FirstName = 'Test%')=0) 
    OR 
    SELECT FirstName, LastName, ID FROM EMPLOYEE WHERE FirstName = 'Test%' 

Je dois revenir à mapper ce NHibernate, est-il un moyen plus rapide efficace de le faire au lieu de faire deux appels de base de données?

+1

Je ne pense pas que vous devez vous soucier de la surcharge de l'écriture de deux appels de base de données. – Juliet

+0

Tant que FirstName et LastName sont tous les deux indexés, à peu près n'importe quelle requête nonstupid sera suffisamment efficace (sauf si votre base de données a des millions d'entrées). – Brian

+0

"donc sélectionnez * de Employé où Prénom = 'test%' ou Nom = 'test'% '. Wont' travail '. Si vous voulez toujours les enregistrements lorsque FirstName correspond (quel que soit le nom LastName), alors il s'agit bien de la requête. Voir ma réponse pour plus de détails. –

Répondre

1

Donnez l'essayer:

SELECT FirstName, LastName, ID FROM EMPLOYEE WHERE FirstName = 'Test%' 
OR (FirstName <> 'Test%' AND LastName = 'Test%') 
+1

FirstName <> 'Test%' est inutile. Faites la table de vérité ... –

0
Select * 
From Employee 
Where FirstName Like @Text + '%' 

Union 

Select * 
From Employee 
Where LastName Like @Text + '%'; 
+0

Les gens vont-ils expliquer pourquoi ils votent? – ChaosPandion

+0

Je n'ai pas downvote, mais je ne pense pas que cela réponde à la question. "La requête devrait d'abord chercher un nom dans le prénom, seulement s'il ne trouve pas de nom de famille." –

+0

Cela servira le but sans être procédural. – ChaosPandion

1
FROM Employee 
WHERE (FirstName LIKE 'Test%' AND LastName NOT LIKE 'Test%') 
OR (LastName LIKE 'Test%' AND firstName NOT LIKE 'Test%') 

Accordé vous ne se soucient pas de quel ordre ils reviennent. Si les enregistrements doivent revenir avec les enregistrements que le premier nom est correct, suivi des noms où le dernier match de nom, cette ne fonctionnera pas.

+0

Sur un ensemble de données de 4000 entrées, cela finit par être deux fois plus rapide, même si vous le saviez probablement déjà. – ChaosPandion

+0

Ceci est spécifiquement sur SQL Server. – ChaosPandion

+0

Cette requête est en HQL. J'ai fait presque exactement ceci sur mon système, accordé il est Hibernate, pas NHibernate, et cela a fonctionné – Zoidberg

1

« L'optimisation prématurée est la racine de tous les maux ». Pourquoi voudriez-vous que la recherche soit faite comme l'optimiseur la voit, au lieu de déclarer ce que vous voulez?
Tout se résume à une table de vérité booléenne: quand correspond FirstName, vous voulez que l'enregistrement (ce qui est dans LastName, un match ou nomatch) et si FirstName ne vous voulez correspond pas, le dossier lors de matchs LastName:

F match, L match => yes 
F match, L nomatch => yes 
F nomatch, L match => yes 
F nomatch, L nomatch => no 

C'est exactement la condition OU: (FirstName matching) OR (LastName matching); les seuls enregistrements ignorés sont lorsque FirstName et LastName ne correspondent pas.

L'optimisation booléenne garantit que la 2ème condition n'est même pas évaluée lorsque la première est vraie.

Ainsi, votre requête est:

SELECT FirstName, LastName, ID 
FROM Employee 
WHERE (FirstName LIKE 'Test%') 
    OR (LastName LIKE 'Test%') 

MISE À JOUR: Je peut avoir mal compris l'objectif si elle est en effet de ne pas retourner un match LastName si les dossiers ont été trouvés avec seulement le ...
FirstName Quoi qu'il en soit , la position sur l'optimisation prématurée est toujours valide ...
Vous avez besoin d'une requête en 2 passes, car vous ne pouvez pas dire si LastName doit être considéré jusqu'à ce que vous soyez sûr que vous n'avez aucune correspondance sur FirstName. Mais avec des index et des statistiques appropriés, l'optimiseur le rendra très efficace.

La requête:

SELECT FirstName, LastName, ID 
FROM Employee 
WHERE (FirstName LIKE 'Test%') 
    OR (LastName LIKE 'Test%' 
     AND (SELECT Count(ID) 
      FROM Employee 
      WHERE FirstName LIKE 'Test%') = 0) 

est légèrement plus cher que le précédent.

0

Je ne pense pas que ces requêtes répondent à la question. Ma compréhension est qu'une recherche sur 'John%' devrait retourner les employés avec le nom de famille John, Johnson, etc. SEULEMENT s'il n'y avait aucun employé avec le prénom John, Johnny, etc.Toutes les requêtes afficheront à la fois John Adams et Lyndon Johnson si la table contient les deux, mais seul John Adams devrait apparaître, car les noms de famille ne doivent correspondre que s'il n'y a pas de prénoms correspondants.

Voici une proposition utilisant la syntaxe SQL Server. Il devrait être possible d'écrire cela dans d'autres dialectes de SQL:

select top (1) with ties 
    FirstName, LastName, ID 
from (
    select 
    0 as SearchLastNames, 
    FirstName, LastName, ID 
    from EMPLOYEE 
    where FirstName like 'Test%' 
    union all 
    select 
    1 as SearchLastNames, 
    FirstName, LastName, ID 
    from EMPLOYEE 
    where LastName like 'Test%' 
) as T 
order by SearchLastNames; 

S'il y a des prénoms correspondant à la valeur de SearchLastNames plus petit sera 0, et le TOP (1) avec des liens .. commande par SearchLastNames sera renvoie des informations uniquement pour les correspondances de prénom (où SearchLastNames est 0).

S'il n'y a pas de prénoms correspondants, la seule valeur SearchLastNames sera 1. Dans ce cas, TOP retournera des informations pour toutes les correspondances de nom (où SearchLastNames vaut 1), s'il y en a.

Un plus maladroit, mais plus de solution portable est ceci:

select 
    FirstName, LastName, ID 
    from EMPLOYEE 
    where FirstName like 'Test%' 
    union all 
    select 
    FirstName, LastName, ID 
    from EMPLOYEE 
    where LastName like 'Test%' 
    and not exists (
    select 
    FirstName, LastName, ID 
    from EMPLOYEE 
    where FirstName like 'Test%' 
); 
Questions connexes