2009-11-25 7 views
1

J'ai une requête suivante (simplifiée):SQL Server: équivalent logique de ALL requête

SELECT 
    Id 
FROM 
    dbo.Entity 
WHERE 
    1 = ALL (
     SELECT 
      CASE 
       WHEN {Condition} THEN 1 
       ELSE 0 
      END 
     FROM 
      dbo.Related 
      INNER JOIN dbo.Entity AS TargetEntity ON 
       TargetEntity.Id = Related.TargetId 
     WHERE 
      Related.SourceId = Entity.Id 
    ) 

{Condition} est une condition dynamique complexe sur TargetEntity. En termes simples, cette requête doit renvoyer des entités pour lesquelles toutes les entités associées correspondent à la condition requise.

Malheureusement, cela ne fonctionne pas très bien, puisque par la norme SQL 1 = ALL est évalué à TRUE lorsque ALL est appliqué à un ensemble vide. Je sais que je peux ajouter AND EXISTS, mais cela exigera que je répète toute la sous-requête, ce qui, j'en suis certain, posera des problèmes de performance.

Comment réécrire la requête pour obtenir le résultat dont j'ai besoin (SQL Server 2008)?

Merci d'avance.

Remarque: en pratique, toute requête est très dynamique, donc la solution idéale serait de réécrire seulement 1 = ALL (...), depuis le changement de haut niveau de sélection peut causer des problèmes lorsque les conditions supplémentaires sont ajoutées à haut niveau où.

Répondre

2

Ne pourriez-vous utiliser un minimum pour y parvenir?

EG:

SELECT 
    Id 
FROM 
    dbo.Entity 
WHERE 
    1 = (
     SELECT 
      MIN(CASE 
       WHEN {Condition} THEN 1 
       ELSE 0 
      END) 
     FROM 
      dbo.Related 
      INNER JOIN dbo.Entity AS TargetEntity ON 
       TargetEntity.Id = Related.TargetId 
     WHERE 
      Related.SourceId = Entity.Id 
    ) 

Le min doit retourner null s'il n'y a pas de clause, 1 s'ils sont tous 1 et 0 s'il y a des des 0, et la comparaison à 1 ne devrait être vrai pour 1.

+0

Ça a l'air génial, je vais essayer ça maintenant. –

+0

Fonctionne très bien, merci. –

0

Il peut être traduit en pick Entities where no related entities with unmatched condition exist.

Ceci peut être accompli par:

SELECT 
    Id 
FROM 
    dbo.Entity 
WHERE 
    NOT EXISTS (
//as far as I have an element which do not match the condition, skip this entity 
     SELECT TOP 1 1 
     FROM 
      dbo.Related 
      INNER JOIN dbo.Entity AS TargetEntity ON 
       TargetEntity.Id = Related.TargetId 
     WHERE 
      Related.SourceId = Entity.Id AND 
      CASE 
       WHEN {Condition} THEN 1 
       ELSE 0 
      END = 0 
    ) 

EDIT: en fonction de l'état, vous pouvez écrire quelque chose comme:
WHERE Related.SourceId = Entity.Id AND NOT {Condition} si elle ne change pas trop la complexité de la requête.

+0

Je pense que s'il n'y a pas d'entités apparentées, NOT EXISTS sera TRUE ici (ce qui est le même problème que je suis avec ALL). –

0

Au lieu d'utiliser all, modifiez votre requête pour comparer le résultat de la sous-requête directement:

select Id 
    from dbo.Entity 
    where 1 = (
     select 
     case 
      when ... then 1 
      else 0 
     end 
     from ... 
     where ... 
    ) 
+0

La sous-requête a renvoyé plus de 1 valeur. Ceci n'est pas autorisé lorsque la sous-requête suit =,! =, <, <= , >,> = ou lorsque la sous-requête est utilisée comme une expression. –

+0

oh ouais - oups - désolé pour la distraction ... – Ray

0

Probablement ceci fonctionne: WHERE NOT 0 = ANY (...)

+0

Non, ne fonctionne pas non plus pour un ensemble vide. 0 = ANY renvoie false pour un ensemble vide (ce qui est attendu), donc NON 0 = ANY renvoie TRUE, ce qui revient à 1 = ALL. –

0

Si je lis la requête correctement, il peut être simplifié à quelque chose comme:

SELECT  e.Id 
FROM   dbo.Entity e 
INNER JOIN dbo.Related r ON r.SourceId = e.Id 
INNER JOIN dbo.Entity te ON te.Id = r.TargetId 
WHERE  <extra where stuff> 
GROUP BY  e.Id 
HAVING  SUM(CASE WHEN {Condition} THEN 1 ELSE 0 END) = COUNT(*) 

Cela signifie que la condition doit être vraie pour toutes les lignes. Il filtre le casse "vide" avec les INNER JOINs.

+0

Cela fonctionne dans le cas donné. Cependant, voir ma note. Il y a des situations où le niveau supérieur peut contenir deux de ces conditions, par exemple. –

+0

@Andrey Shchekin: Celui-ci supporte aussi WHERE (édité). De toute façon, la réponse de fyjham est plutôt bonne – Andomar