Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

A consulta SQL IN produz um resultado estranho


Esse comportamento, embora não intuitivo, está muito bem definido na Base de Conhecimento da Microsoft:

KB #298674:problema:a subconsulta resolve nomes de colunas para tabelas externas

Desse artigo:
CREATE TABLE X1 (ColA INT, ColB INT)
CREATE TABLE X2 (ColC INT, ColD INT)
SELECT ColA FROM X1 WHERE ColA IN (Select ColB FROM X2)
SELECT ColA FROM X1 WHERE ColA in (Select X2.ColB FROM X2)

As pessoas reclamam desse problema há anos, mas a Microsoft não vai corrigi-lo. Está, afinal, em conformidade com a norma, que afirma essencialmente:

Mais informações nos seguintes "bugs" do Connect, juntamente com várias confirmações oficiais de que esse comportamento ocorre por design e não será alterado (portanto, você terá que alterar o seu - ou seja, sempre usar aliases ):

Connect #338468 :A resolução do nome da coluna CTE na subconsulta não é validada
Connect #735178 :Subconsulta T-SQL não funciona em alguns casos quando o operador IN é usado
Connect #302281 :Coluna inexistente faz com que a subconsulta seja ignorada
Connect #772612 :Erro de alias não relatado quando dentro de um operador IN
Connect #265772 :Bug usando sub selecione

No seu caso, esse "erro" provavelmente será muito menos provável de ocorrer se você usar nomes mais significativos do que ID, OID e PID. O Order.PID aponte para Person.id ou Person.PID ? Projete suas tabelas para que as pessoas possam descobrir os relacionamentos sem precisar perguntar a você. Um PersonID deve ser sempre um PersonID , não importa onde esteja no esquema; o mesmo com um OrderID . Economizar alguns caracteres de digitação não é um bom preço a pagar por um esquema completamente ambíguo.

Você pode escrever um EXISTS cláusula em vez disso:
... FROM dbo.Person AS p WHERE EXISTS 
(
  SELECT 1 FROM dbo.[Order] AS o
  WHERE o.PID = p.id -- or is it PID? See why it pays to be explicit?
);