web-dev-qa-db-fra.com

Jointure gauche avec condition

Supposons que j'ai ces tables

create table bug (
    id int primary key, 
    name varchar(20)
)
create table blocking (
    pk int primary key,
    id int, 
    name varchar(20)
)

insert into bug values (1, 'bad name')
insert into bug values (2, 'bad condition')
insert into bug values (3, 'about box')
insert into blocking values (0, 1, 'qa bug')
insert into blocking values (1, 1, 'doc bug')
insert into blocking values (2, 2, 'doc bug')

et je voudrais joindre les tables sur les colonnes id et le résultat devrait être comme ceci:

id          name                 blockingName
----------- -------------------- --------------------
1           bad name             qa bug
2           bad condition        NULL
3           about box            NULL

Cela signifie: je voudrais retourner toutes les lignes de #bug, il ne devrait y avoir que la valeur 'qa bug' dans la colonne 'blockingName' ou NULL (si aucune ligne correspondante dans #blocking n'a été trouvée)


Ma sélection naïve était comme ça:

select * from #bug t1 
    left join #blocking t2 on t1.id = t2.id
    where t2.name is null or t2.name = 'qa bug'

mais cela ne fonctionne pas, car il semble que la condition soit d'abord appliquée à la table #blocking, puis elle est jointe.

Quelle est la solution la plus simple/typique pour ce problème? (J'ai une solution avec la sélection imbriquée, mais j'espère qu'il y a quelque chose de mieux)

21
stej

Mettez simplement les critères "qa bug" dans la jointure:

select t1.*, t2.name from #bug t1 
left join #blocking t2 on t1.id = t2.id AND t2.name = 'qa bug'
42
samjudson

la sélection correcte est:

create table bug (
id int primary key, 
name varchar(20)
)
insert into bug values (1, 'bad name')
insert into bug values (2, 'bad condition')
insert into bug values (3, 'about box')

CREATE TABLE blocking
(
pk int IDENTITY(1,1)PRIMARY KEY ,
id int, 
name varchar(20)
)
insert into blocking values (1, 'qa bug')
insert into blocking values (1, 'doc bug')
insert into blocking values (2, 'doc bug')


select 
t1.id, t1.name,
(select  b.name from blocking b where b.id=t1.id and b.name='qa bug')
from bug t1 
3
ludek janicek

Il semble que vous ne souhaitiez sélectionner qu'une seule ligne parmi #blocking et joignez-le à #bug. Je ferais:

select t1.id, t1.name, t2.name as `blockingName` 
from `#bug` t1
left join (select * from `#blocking` where name = "qa bug") t2
on t1.id = t2.id
2
Matt Fenwick
select * 
from #bug t1 
left join #blocking t2 on t1.id = t2.id and t2.name = 'qa bug'
2
StevieG

assurez-vous que la requête interne ne renvoie qu'une seule ligne. Vous devrez peut-être ajouter un top 1 s'il en renvoie plus d'un.

select 
t1.id, t1.name,
(select  b.name from #blocking b where b.id=t1.id and b.name='qa bug')
from #bug t1 
1
Diego

Voici une démo: http://sqlfiddle.com/#!2/414e6/1

select
  bug.id,
  bug.name,
  blocking.name as blockingType
from
  bug
    left outer join blocking on
      bug.id = blocking.id AND
      blocking.name = 'qa bug'
order by
  bug.id

En ajoutant la clause "blocking.name" sous la jointure externe gauche, plutôt que dans le where, vous indiquez qu'elle doit également être considérée comme "externe" ou facultative. Lorsqu'elle fait partie de la clause where, elle est considérée comme obligatoire (c'est pourquoi les valeurs nulles ont été filtrées).

BTW - sqlfiddle.com est mon site.

1
Jake Feasel