2010-04-16 24 views
24

Ho una tabella di nomi e indirizzi, che include una colonna del codice postale. Voglio rimuovere gli spazi dai codici postali e selezionare quelli che corrispondono a un particolare modello. Sto cercando questo (semplificato un po ') in T-SQL in SQL Server 2005:SELECT with a Replace()

SELECT Replace(Postcode, ' ', '') AS P 
FROM Contacts 
WHERE P LIKE 'NW101%' 

Ma ho il seguente errore;

Msg 207, Level 16, State 1, Line 3 
Invalid column name 'P'. 

Se rimuovo la clausola WHERE ho un elenco di codici postali senza spazi, che è quello che voglio per la ricerca. Come dovrei avvicinarmi a questo? Che cosa sto facendo di sbagliato?

+1

si potrebbe creare una vista indicizzata materializzata, dove Sostituisci sarebbe precalcolate e parte di un indice di fisica, e si potrebbe cercare fuori che senza modificare i dati o tabella originale. –

risposta

32

Non utilizzare l'alias (P) nella clausola WHERE direttamente.

È possibile utilizzare lo stesso REPLACE logica di nuovo nella clausola WHERE:

SELECT Replace(Postcode, ' ', '') AS P 
FROM Contacts 
WHERE Replace(Postcode, ' ', '') LIKE 'NW101%' 

Oppure utilizzare una query sub alias come descritto nelle risposte di Nick.

+0

Questo non funzionerà se 'Codice postale 'inizia con spazi. –

+0

Questo non fa ciò che l'OP ha bisogno ... sta cercando di usare un 'LIKE' sulla versione senza spazi ... –

+0

Grazie Odd! Per me va bene. –

11

È possibile fare riferimento è in questo modo se si avvolgono la query, in questo modo:

SELECT P 
FROM (SELECT Replace(Postcode, ' ', '') AS P 
     FROM Contacts) innertable 
WHERE P LIKE 'NW101%' 

essere sicuri di dare il avvolto selezionare un alias, anche non utilizzato (SQL Server non lo consente senza uno IIRC)

2

Si sta creando un alias P e in seguito nella clausola where si sta utilizzando lo stesso, che è ciò che sta creando il problema. Non utilizzare P in where, provate questo invece:

SELECT Replace(Postcode, ' ', '') AS P FROM Contacts 
WHERE Postcode LIKE 'NW101%' 
2

Devi ripetere la tua espressione ovunque si desidera utilizzarlo:

SELECT Replace(Postcode, ' ', '') AS P 
FROM Contacts 
WHERE Replace(Postcode, ' ', '') LIKE 'NW101%' 

o si può fare una sottoquery

select P 
from (
SELECT Replace(Postcode, ' ', '') AS P 
FROM Contacts 
) t 
WHERE P LIKE 'NW101%' 
2

Per espandere su Oded's answer, il modello concettuale necessita di una leggera regolazione qui. L'aliasing dei nomi delle colonne (clausole AS nell'elenco SELECT) avviene molto tardi nell'elaborazione di un SELECT, motivo per cui i nomi alias non sono disponibili per le clausole WHERE. In realtà, l'unica cosa che accade dopo colonna di aliasing è l'ordinamento, che è il motivo (per citare la documentazione sul SELECT):

column_alias può essere utilizzato in una clausola ORDER BY. Tuttavia, non può essere utilizzato in una clausola WHERE, o HAVING.

Se si dispone di un'espressione contorta nella lista SELECT, si può essere preoccupati 'in corso di valutazione per due volte' quando appare nell'elenco SELECT e (diciamo) una clausola WHERE - tuttavia, il motore di query è intelligente abbastanza per capire cosa sta succedendo.Se si vuole evitare di avere l'espressione compare due volte nella query, si può fare qualcosa di simile

SELECT c1, c2, c3, expr1 
FROM 
    (SELECT c1, c2, c3, some_complicated_expression AS expr1) inner 
WHERE expr1 = condition 

che evita some_complicated_expression apparire fisicamente due volte.

+0

+1 Grazie per la chiara spiegazione Aakash. Penso che, inconsciamente, stavo evitando di ripetere Replace(); e questo probabilmente mi ha impedito di vedere la soluzione corretta. Grazie! –

+0

Questa dovrebbe essere la risposta corretta. Fondamentalmente, WHERE è in fase di elaborazione prima di SELECT. Quindi, la clausola WHERE non dovrebbe essere a conoscenza dell'esistente della colonna che è aliasata come P. Inoltre, poiché la colonna P è un valore calcolato, l'utilizzo dell'approccio di subquery sarebbe una delle soluzioni di confronto a fare di Replace() due volte . – frostshoxx

2
SELECT * 
FROM Contacts 
WHERE ContactId IN 
    (SELECT a.ContactID 
    FROM 
     (SELECT ContactId, Replace(Postcode, ' ', '') AS P 
     FROM Contacts 
     WHERE Postcode LIKE '%N%W%1%0%1%') a 
    WHERE a.P LIKE 'NW101%') 
3

se si vuole sperare di utilizzare sempre un indice, memorizzare i dati in modo coerente (con gli spazi rimossi). O semplicemente rimuovi gli spazi o aggiungi una colonna calcolata persistente, quindi puoi semplicemente selezionare da quella colonna e non dover aggiungere tutto lo spazio per la rimozione ogni volta che esegui la query.

aggiungere una colonna calcolata persistente:

ALTER TABLE Contacts ADD PostcodeSpaceFree AS Replace(Postcode, ' ', '') PERSISTED 
go 
CREATE NONCLUSTERED INDEX IX_Contacts_PostcodeSpaceFree 
ON Contacts (PostcodeSpaceFree) --INCLUDE (covered columns here!!) 
go 

per fissare solo la colonna, eliminando gli spazi d'uso:

UPDATE Contacts 
    SET Postcode=Replace(Postcode, ' ', '') 

Ora è possibile cercare in questo modo, sia SELECT può utilizzare un indice:

--search the PERSISTED computed column 
SELECT 
    PostcodeSpaceFree 
    FROM Contacts 
    WHERE PostcodeSpaceFree LIKE 'NW101%' 

o

--search the fixed (spaces removed column) 
SELECT 
    Postcode 
    FROM Contacts 
    WHERE PostcodeLIKE 'NW101%' 
+0

Grazie per aver dedicato del tempo a questa grande spiegazione, KM. Sfortunatamente il database in questione fa parte di un sistema "legacy" che devo trattare come di sola lettura. Ma apprezzo il tuo punto sull'indicizzazione. Non ero a conoscenza di colonne calcolate persistenti, quindi ho imparato qualcosa. Grazie! –

0

Ciò funzionerà:

SELECT Replace(Postcode, ' ', '') AS P 
FROM Contacts 
WHERE Replace(Postcode, ' ', '') LIKE 'NW101%'