Situação
Estou fazendo uma consulta SQL server para filtrar dados da tabela de projetos ( tblProjecten
) . Esta tabela tem muitos relacionamentos com outras tabelas, como region ( tblProjectenRegio
) , organization ( tblProjectenOrganisatie
) , etc.
Todos os parâmetros que declaro são opcionais. Eu encontrei para usar coalesce
para fazer isso. Funciona bem se eu não usar as junções dentro da minha consulta aqui, você obteve minha consulta que usei primeiro:
declare @themaid int = 1 ; -- themeID
declare @trefwoord nvarchar(max) = '' ; -- search query
select distinct p.*
from tblProjecten p left join tblProjectenThema pt on p.projectId = pt.projectId
where pt.themaId = coalesce(@themaid, pt.themaId) and
p.naam like '%' + @trefwoord + '%' ;
Abaixo meus resultados para as diferentes declarações (veja também os dados abaixo) :
@a empregada | @trefwood | resultados | correto |
---|---|---|---|
1 | 166 | OK | |
1 | ar condicionado | 166 | OK |
nulo | ar condicionado | 166 | OK |
nulo | 166, 185, 415 | OK |
Isso funciona bem, mas se eu adicionar outros parâmetros condicionais, como consulta abaixo. Eu tenho resultados totalmente outros.
declare @themaid int = 1 ;
declare @studiegebiedid int = null ;
declare @opleidingdtypeid int = null ;
declare @doelgroepid int = null ;
declare @organisatorid int = null ;
declare @regioid int = null ;
declare @trefwoord nvarchar(max) = '' ;
select distinct p.*
from tblProjecten p left join tblProjectenThema pt on p.projectId = pt.projectId
left join tblProjectenStudiegebieden ps on p.projectId = ps.projectid
left join tblProjectenOpleidingsType pot on p.projectId = pot.projectID
left join tblProjectendoelgroep pd on p.projectId = pd.projectId
left join tblProjectenOrganisator po on p.projectId = po.projectId
left join tblProjectenRegio pr on p.projectId = pr.projectId
where pt.themaId = coalesce(@themaid, pt.themaId) and
ps.studiegebiedid = coalesce(@studiegebiedid, ps.studiegebiedid) and
pot.opleidingsID = coalesce(@opleidingdtypeid, pot.opleidingsID) and
pd.doelgroepId = coalesce(@doelgroepid, pd.doelgroepid) and
po.organisatorId = coalesce(@organisatorid, po.organisatorId) and
pr.regioId = coalesce(@regioid, pr.regioId) and
p.naam like '%' + @trefwoord + '%' ;
Aqui estão os resultados (as outras declarações são null
) :
@a empregada | @trefwood | resultados | correto | devemos ser |
---|---|---|---|---|
1 | NÃO ESTÁ TUDO BEM | 166 | ||
1 | ar condicionado | NÃO ESTÁ TUDO BEM | 166 | |
nulo | ar condicionado | NÃO ESTÁ TUDO BEM | 166 | |
nulo | NÃO ESTÁ TUDO BEM | 166, 185, 415 |
Isso ocorre porque as outras tabelas não possuem nenhum dado dentro dela. (veja os dados abaixo)
Pergunta
Minha pergunta agora é posso ignorar as junções sem nenhum resultado para fazer a última consulta funcionar?
Eu também tentei usar junções internas e direitas, mas deu os mesmos resultados.
Dados
Aqui você tem alguns dados:
tblProjecten
:
ID do projeto | naam |
---|---|
166 | Atestando AIRCO PROJECT |
185 | Autoweb E-LEARNING |
415 | Bouw en Hout |
tblProjectenThema
:
a empregada | ID do projeto |
---|---|
1 | 166 |
2 | 166 |
2 | 415 |
3 | 415 |
6 | 185 |
tblProjectendoelgroep
:
doelgroepId | ID do projeto |
---|
Estive lendo e relendo a pergunta original. O que eu cheguei é isso:
Retorna registros de tblProjecten onde existem correspondências para parâmetros que foram fornecidos (não são nulos). Onde os parâmetros não são fornecidos (ou nulos), assuma todas as correspondências para essa tabela filho
Efetivamente, você está tornando suas associações dinâmicas com base no fato de um parâmetro ter um valor fornecido ou não.
Para isso você pode usar:
Eu mudei um pouco as coisas. Em vez de fazer joins, estamos fazendo um
EXISTS
com uma subconsulta correlacionada.Cada um avalia como:
Ao fazer isso, nossas junções se tornam efetivamente opcionais (dependendo se temos um valor de parâmetro ou não).
Se eu tiver sua intenção original correta, uma suposição fácil é que você pode querer usar junções internas, por exemplo:
A razão pela qual você não pode fazer isso é que tblProjectenThema pode estar vazio e, portanto, nenhuma linha pode ser correspondida. Você sempre obteria um resultado vazio.
Abordagem alternativa
A consulta acima começará a sofrer com o desempenho, pois mais tabelas precisam ser consideradas. Você poderia usar
OPTION(RECOMPILE)
contra a consulta. Como você deseja parâmetros opcionais e dinâmicos, isso também pode ser atendido usando SQL dinâmico.Eu acho que você está usando
LEFT
joins incorretamente. Do jeito que a consulta está agora, com uma coluna de cada tabela envolvida naWHERE
cláusula, as junções atuam efetivamente comoINNER
junções, nãoLEFT
junções. Como @Kent explicou no comentário:Quando a condição está na instrução de junção (a
ON
parte), a restrição é aplicada antes da junção. Quando está noWHERE
, é aplicado após a ocorrência da junção (portanto, se você colocar uma condição sobre a tabela correta, a junção efetivamente se tornará uma junção interna).Agora, eu não tenho certeza sobre o que exatamente é desejado.
Caso A (provavelmente não é o desejado). Se você também deseja informações das outras tabelas, deve:
WHERE
para as respectivasON
condiçõesCOALESCE()
funçõesDISTINCT
A consulta seria algo como:
Caso B (acho que é isso). Se você deseja "parâmetros opcionais", ou seja, quando os parâmetros são nulos para não restringir os resultados, você deve:
WHERE
condições emEXISTS
subconsultasCOALESCE()
funções e usarOR @parameter IS NULL
)DISTINCT
A consulta seria algo como: