Domanda

Durante la revisione del codice mi sono imbattuto in qualcosa di strano, qualcuno aveva letto che puoi usare ABS(CHECKSUM(NewId())) % N per procurarti numeri casuali da 0 a N-1 (come RAND() non si verifica per file), ma sospetto che non abbiano davvero testato il loro codice (semplificato ora con le variabili della tabella e il codice effettivo ha fatto un TOP 1 country Per aggirare erroneamente un problema di seguito):

DECLARE @Values TABLE
(
    id int identity,
    country VARCHAR(100)
)

INSERT INTO @Values (country) VALUES ('UK'), ('USA'), ('China')

SELECT *, (SELECT country FROM @Values v WHERE v.id = ABS(CHECKSUM(NewId())) % 3 + 1)
FROM @Values

Quando si esegue il seguente errore:

La sottoquery ha restituito più di 1 valore. Questo non è consentito quando la sottocquery segue = ,! =, <, <=,>,> = o quando la sottocquery è usata come espressione.

La mia prima domanda è stata come può la sottoquery restituire più di un valore? E com'è che alcune volte non restituisce alcun valore? (Nota non è la domanda che sto ponendo a così) testato da:

SELECT country FROM @Values v WHERE v.id = ABS(CHECKSUM(NewId())) % 3 + 1

Eppure non importa quante volte viene eseguito i seguenti:

SELECT ABS(CHECKSUM(NewId())) % 3 + 1

I risultati restituiti sono sempre 1,2,3 (questo era il "test" che il programmatore aveva usato quando scriveva il loro codice)

Da tutto ciò, sospetto che ciò sia perché viene riesaminato per ogni confronto e non ogni riga, qualcuno può confermarlo e fornire un buon collegamento per spiegare questo comportamento in modo da poterlo sottolineare?

È stato utile?

Soluzione

Perché, questo è previsto.

ABS(CHECKSUM(NewId())) % 3 + 1 viene valutato una volta per ogni riga in @Values, e quindi ha valori diversi per ogni riga.

Quindi può restituire più righe o nessuna riga.

Questo è esattamente ciò che dovresti aspettarti quando si dice, questa espressione valuta per ogni riga.

Apparentemente quello che vuoi effettivamente è un'espressione che valuta una volta per query.

Altri suggerimenti

NewID verrà sempre chiamato una volta per riga, se hai bisogno di un valore unico, usa qualcosa come:

ROUND(((3) * RAND() + 1), 0)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top