Estou tentando construir uma cláusula where que exija que um número X de filhos tenha uma relação com um pai específico com um relacionamento N para N. Algo semelhante a "Receba todos os recibos onde esses produtos foram vendidos juntos". Um cenário de exemplo é mais fácil de explicar:
DECLARE @Nodes TABLE(
Id INT
);
DECLARE @Arc TABLE(
Id INT IDENTITY(1,1),
Source INT, -- FK @Nodes.Id
Dest INT -- FK @Nodes.Id
);
INSERT INTO @Nodes (Id) VALUES (1),(2),(3),(4);
INSERT INTO @Arc (Source, Dest) VALUES
(1, 2)
,(1, 3)
,(1, 3)
,(2, 1)
,(2, 3)
,(2, 4);
No SP, a entrada é pré-processada em uma tabela como esta:
DECLARE @InputConnectedNodes TABLE ( Id INT );
INSERT INTO @InputConnectedNodes (Id) VALUES (3),(4); -- not a fixed number of nodes
Neste exemplo, queremos todos os nós que tenham um arco para os nós 3 e 4 (somente o nó 2 no exemplo acima). Atualmente temos isso:
SELECT DISTINCT Source
FROM @Arc
WHERE Dest IN (SELECT Id FROM @InputConnectedNodes);
Em seguida, temos um código processual feio que percorre a entrada e a saída (aninhada) verificando todos os relacionamentos. Eu gostaria de substituí-lo por algo declarativo. O melhor que consegui até agora é este:
SELECT Source
FROM @Arc
WHERE Dest IN (SELECT Id FROM @InputConnectedNodes)
GROUP BY Source
HAVING COUNT(Source) = (SELECT COUNT(*) FROM @InputConnectedNodes)
Mas falhará quando os nós tiverem vários arcos (idênticos) como (1->3) no meu exemplo.
Eu também poderia resolver isso gerando dinamicamente uma cláusula where, mas prefiro uma solução totalmente declarativa.
Sugiro afrouxar sua determinação para uma solução totalmente declarativa. Pode não haver uma maneira declarativa de resolver seu problema e há muitos casos em que o SQL dinâmico é uma solução muito melhor em termos de desempenho - mesmo que falte legibilidade.
O SQL dinâmico dá ao otimizador a oportunidade de usar diferentes planos otimizados para diferentes parâmetros, em vez de ter que criar um único plano que resolva bem todas as permutações. Este último é bastante difícil de alcançar.
Seu problema é chamado de divisão relacional . Veja as perguntas nessa tag e:
A maioria das soluções Stack Overflow funcionaria como está ou com pequenas modificações para o SQL Server. Observe como as consultas mais complicadas, com várias junções ou
EXISTS
subconsultas (que precisariam de código produzido dinamicamente para os casos arbitrários) são mais eficientes do que aGROUP BY
consulta.