2010-02-04 10 views
31

J'ai une inscriptionRejoignez SQL interne sur des valeurs nulles

SELECT * FROM Y 
INNER JOIN X ON ISNULL(X.QID, 0) = ISNULL(y.QID, 0) 

Isnull dans une jointure comme cela rend lent. C'est comme avoir une jointure conditionnelle. Y a-t-il du travail pour quelque chose comme ça? j'ai beaucoup de dossiers où QID est nul

quelqu'un a un travail autour qui n'implique pas modifier les données

+2

Pour quelle base de données (y compris la version)? –

+0

Seuls SQL Server et Access ont 'ISNULL()', donc je supposerais SQL Server –

+0

Base de données: sql 2005 – Rico

Répondre

50

Vous avez deux options

INNER JOIN x ON x.qid = y.qid OR (x.qid IS NULL AND y.qid IS NULL)

ou plus facile

INNER JOIN x ON x.qid IS NOT DISTINCT FROM y.qid

+0

qui est plus rapide en cours d'exécution? – Rico

+0

Certainement, le 'IS NOT DISTINCT FROM' ne peut pas être plus lent, donc je voudrais aller avec. Mais aucun de ceux-ci ne devrait être/lent /. Vous devriez parler d'un ensemble de données assez important pour que cela compte. –

+0

hmm evan que vous pouvez probablement comprendre c'est une version plus petite d'une vue beaucoup plus grande. Comme vous l'avez dit, ce qui est montré ci-dessus est un problème novice qui s'est éloigné de moi. Bien que je ne veuille pas diffuser ma vue partout, avez-vous une minute pour la regarder et peut-être m'aider à réparer la plaie ... – Rico

-1

Fondamentalement, vous voulez j oin deux tables ensemble où leurs colonnes QID sont à la fois pas null, correct? Cependant, vous n'appliquez aucune autre condition, telle que les deux valeurs QID (ce qui me semble étrange, mais d'accord). Quelque chose d'aussi simple que les éléments suivants (testé MySQL) semble faire ce que vous voulez:

SELECT * FROM `Y` INNER JOIN `X` ON (`Y`.`QID` IS NOT NULL AND `X`.`QID` IS NOT NULL); 

Cela vous donne toutes les lignes non nulle en Y joint à chaque ligne non nulle dans X.

Mise à jour: Rico dit qu'il veut aussi les lignes avec des valeurs NULL, pourquoi pas seulement:

SELECT * FROM `Y` INNER JOIN `X`; 
+0

C'est incorrect ... si ay était y.qid = x.qid il me donnera seulement des lignes qui ne sont pas nulles. Je veux les lignes où elles sont toutes les deux nulles aussi bien. – Rico

+0

Ok, ce n'était pas clair pour moi. – pr1001

+0

laissez-moi voir si je peux trouver un exemple plus précis pour effacer les problèmes – Rico

8

Êtes-vous engagé à utiliser la syntaxe INNER JOIN?

Sinon, vous pouvez utiliser cette syntaxe alternative:

SELECT * 
FROM Y,X 
WHERE (X.QID=Y.QID) or (X.QUID is null and Y.QUID is null) 
+1

Il n'y a aucun avantage à utiliser cette syntaxe plutôt que la jointure explicite dans la réponse acceptée. –

3

Je suis assez sûr que la jointure ne même pas faire ce que vous voulez. S'il y a 100 enregistrements dans la table a avec un qid nul et 100 enregistrements dans la table b avec un qid nul, alors la jointure comme écrite devrait faire une jointure croisée et donner 10 000 résultats pour ces enregistrements. Si vous regardez le code suivant et exécutez les exemples, je pense que le dernier est probablement plus le jeu de résultats que l'intention:

create table #test1 (id int identity, qid int) 
create table #test2 (id int identity, qid int) 

Insert #test1 (qid) 
select null 
union all 
select null 
union all 
select 1 
union all 
select 2 
union all 
select null 

Insert #test2 (qid) 
select null 
union all 
select null 
union all 
select 1 
union all 
select 3 
union all 
select null 


select * from #test2 t2 
join #test1 t1 on t2.qid = t1.qid 

select * from #test2 t2 
join #test1 t1 on isnull(t2.qid, 0) = isnull(t1.qid, 0) 


select * from #test2 t2 
join #test1 t1 on 
t1.qid = t2.qid OR (t1.qid IS NULL AND t2.qid IS NULL) 


select t2.id, t2.qid, t1.id, t1.qid from #test2 t2 
join #test1 t1 on t2.qid = t1.qid 
union all 
select null, null,id, qid from #test1 where qid is null 
union all 
select id, qid, null, null from #test2 where qid is null 
+0

Ma jointure actuelle fait ce que je veux juste le fait de manière inefficace. – Rico

+0

Par curiosité pourquoi voulez-vous une jointure croisée sur les id Nuls? – HLGEM

1

Si vous voulez des valeurs NULL à inclure de Y.QID alors plus rapide est

SELECT * FROM Y LEFT JOIN X ON y.QID = X.QID

Remarque: cette solution est applicable uniquement si vous avez besoin des valeurs nULL de la table gauche Y-à-dire (en cas ci-dessus).

Sinon INNER JOIN x ON x.qid IS NOT DISTINCT FROM y.qid est bonne façon de faire

-1

Vous pouvez également utiliser la fonction coalesce. J'ai testé cela dans PostgreSQL, mais il devrait également fonctionner pour MySQL ou MS SQL server.

INNER JOIN x ON coalesce(x.qid, -1) = coalesce(y.qid, -1) 

Cela remplacera NULL avec -1 avant de l'évaluer.Par conséquent, il ne doit pas y avoir -1 dans qid.

5

This article has a good discussion on this issue. Vous pouvez utiliser

SELECT * 
FROM Y 
INNER JOIN X ON EXISTS(SELECT X.QID 
         INTERSECT 
         SELECT y.QID); 
+0

Toute comparaison sur les plans de requête à ce sujet par rapport 'ISNULL()'? Je ne pouvais pas voir beaucoup de différence sur un échantillon de données, mais j'aime la simplicité pour les jointures multicolonnes. –

+0

@ThomasG.Mayfield - 'ISNULL' tue l'utilisation de l'index. par exemple. comparer les plans de 'CREATE TABLE #T (X INT UNIQUE); SELECT * FROM #T T1 INNER MERGE REJOINDRE #T T2 ON EXISTE (SELECT T1.X INTERSECT SELECT T2.X); SELECT * DE #T T1 INNER MERGE REJOINDRE #T T2 ON ISNULL (T1.X, -1) = ISNULL (T2.X, -1); SELECT * FROM #T T1 BOUCLE INTERNE JOINDRE #T T2 ON EXISTE (SELECT T1.X INTERSECT CHOISIR T2.X); SELECT * DE #T T1 BOUCLE INTERNE JOINDRE #T T2 ON ISNULL (T1.X, -1) = ISNULL (T2.X, -1); DROP TABLE # T' - la version de fusion ne peut pas utiliser l'ordre d'index et nécessite un tri et les boucles imbriquées balaye l'entrée interne plutôt que de la rechercher . –

+0

J'ai utilisé cette astuce croisée tout le temps, mais il semble que l'optimiseur SQL Server 2016 n'aime pas beaucoup. Je dois enquêter plus si, –