Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

SQL Server:riga presente in una query, mancante in un'altra

Dimostrazione di una possibile spiegazione.

Crea script tabella

SELECT *
INTO #T
 FROM master.dbo.spt_values

 CREATE NONCLUSTERED INDEX [IX_T] ON  #T ([name] DESC,[number] DESC);

Query uno (restituisce 35 risultati)

WITH cte AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY NAME) AS rn
 FROM  #T
)
SELECT c1.number,c1.[type] 
FROM cte c1
JOIN cte c2 ON c1.rn=c2.rn AND c1.number <> c2.number

Query due (come prima ma aggiungendo c2.[tipo] all'elenco di selezione si ottengono 0 risultati);

WITH cte AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY NAME) AS rn
 FROM  #T
)
SELECT c1.number,c1.[type] ,c2.[type] 
FROM cte c1
JOIN cte c2 ON c1.rn=c2.rn AND c1.number <> c2.number

Perché?

row_number() per i NAME duplicati non è specificato, quindi sceglie semplicemente quello che si adatta al miglior piano di esecuzione per le colonne di output richieste. Nella seconda query questo è lo stesso per entrambe le invocazioni di cte, nella prima sceglie un percorso di accesso diverso con una diversa numerazione_riga risultante.

Soluzione suggerita

Ti stai unendo automaticamente al CTE su ROW_NUMBER() over (order by t.[Date])

Contrariamente a quanto ci si poteva aspettare, il CTE probabilmente non essere materializzato che avrebbe assicurato la coerenza per l'auto join e quindi si presume una correlazione tra ROW_NUMBER() su entrambi i lati che potrebbero non esistere per i record in cui è duplicato un [Date] esiste nei dati.

Cosa succede se provi ROW_NUMBER() over (order by t.[Date], t.[id]) per garantire che, in caso di date vincolate, row_numbering sia in un ordine coerente garantito. (O qualche altra colonna/combinazione di colonne che può differenziare i record se id non lo farà)