Domanda

Ho una dichiarazione che seleziona la sottostringa di un charindex come segue:

SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)...
WHERE 
CHARINDEX('ABC', StringField) > 5
.

Quando eseguo la dichiarazione di cui sopra in una query di selezione, i risultati vengono restituiti bene.Quando eseguo la dichiarazione di cui sopra in una vista indicizzata su uno schema, ottengo questo errore:

Invalid length parameter passed to the LEFT or SUBSTRING function
.

Per risolvere il problema scriverò una funzione per ottenere il massimo del charindex e 0 per rimuovere le possibilità di un valore negativo.Ma qualcuno sa perché la clausola WHERE non filtrasse l'istruzione SELECT?

È stato utile?

Soluzione

Perché l'ordine delle operazioni dietro le quinte in una query non è garantita.

Suppongo se si controlla il piano di esecuzione vedrai che sta facendo entrambi i controlli in parallelo - questo perché nessuna operazione può utilizzare un indice!

SQL ha bisogno di caricare ogni riga di quel campo in memoria comunque, quindi lo sta elaborando per entrambi i criteri allo stesso tempo.

È possibile provare WITH (MAXDOP(1)) come suggerimento di query per vedere se ciò mantiene il problema da comparare, oppure è possibile eseguire una sottosecuzione per forzare l'ordine di esecuzione:

SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)...
FROM (
      SELECT Stringfield 
      FROM Table 
      WHERE CHARINDEX('ABC', StringField) > 5
      ) as [X]
.

Ho avuto una questione simile una volta quando stavo controllando di vedere se un campo è stato numerico utilizzando PATINDEX e una delle colonne in my panorama è stata convertendolo in un int - ho ricevuto errori di conversione perché il motore stava convertendo ogni riga dal mioI filtri non erano sargabili.

Altri suggerimenti

Questa è una brutta soluzione alternativa ma potresti fare qualcosa come questo forse:

DECLARE @x TABLE(StringField VARCHAR(32));

INSERT @x SELECT 'ABC'
UNION ALL SELECT 'A'
UNION ALL SELECT 'AAAAAAAABC';

SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)
FROM @x
WHERE CHARINDEX('ABC', StringField) > 5;

SELECT SUBSTRING(StringField,
    CASE WHEN CHARINDEX('ABC', StringField) > 5 THEN 5 ELSE 1 END,
    CHARINDEX('ABC', StringField) - 
    CASE WHEN CHARINDEX('ABC', StringField) > 5 THEN 5 ELSE 0 END)
FROM @x
WHERE CHARINDEX('ABC', StringField) > 5;
.

Entrambi rendimento:

---
AAA
.

Ma sospetto che quest'ultimo sarà consentito in vostra vista.È brutto ma sfortunatamente a meno che non si scarica i dati filtrati in un #temp da prima (o provare a vedere se MAXDOP rimuove in modo affidabile il problema) che non avrai molto controllo su ordinazione di elaborazione.

Un'altra idea è di provare a mettere una colonna calcolata nella tabella (ma non sono sicuro che ti aiuterà se si sta tentando di creare una vista indicizzata - ci possono ancora essere complicazioni).O per utilizzare un indice filtrato con quell'espressione, invece di una vista indicizzata.Ci potrebbero essere diverse "soluzioni" se sappiamo cosa è destinata la vista indicizzata per realizzare e quale versione di SQL Server si sta utilizzando.

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