Come imposto a SQL Server 2005 di eseguire un join prima di dove?
-
10-07-2019 - |
Domanda
Ho una query SQL che unisce una tabella dei prezzi a una tabella contenente le risposte fornite dall'utente. La mia query viene utilizzata per ottenere il prezzo in base alla quantità immessa. Di seguito è la mia istruzione SQL:
SELECT JobQuestion.Value, Price.Min, Price.Max, Price.Amount FROM Price
INNER JOIN JobQuestion
ON Price.QuestionFK=JobQuestion.QuestionFK
AND JobQuestion.JobFK=1
WHERE Price.Min <= JobQuestion.Value
AND Price.Max >= JobQuestion.Value
Il problema è che SQL Server sta eseguendo la clausola where prima del JOIN e sta generando l'errore:
Conversione non riuscita durante la conversione di valore varchar 'TEST' per il tipo di dati int.
perché sta effettuando i confronti minimo e massimo prima del join ('TEST' è un valore immesso dall'utente valido nella tabella JobQuestion, ma non deve essere restituito quando JobQuestion è unito a Price). Credo che SQL Server stia scegliendo di eseguire WHERE perché per qualche motivo il parser ritiene che sarebbe una query più efficiente. Se ho appena eseguito
SELECT JobQuestion.Value, Price.Min, Price.Max, Price.Amount FROM Price
INNER JOIN JobQuestion
ON Price.QuestionFK=JobQuestion.QuestionFK
AND JobQuestion.JobFK=1
Ricevo questi risultati:
500 1 500 272.00
500 501 1000 442.00
500 1001 2000 782.00
Quindi, l'aggiunta di WHERE dovrebbe filtrare gli ultimi due e restituire semplicemente il primo record. Come posso forzare SQL a eseguire prima JOIN o utilizzare un'altra tecnica per filtrare solo i record di cui ho bisogno?
Soluzione
Innanzitutto, questo è molto probabilmente un segno di design scadente.
Se non riesci a modificare lo schema, forse potresti forzare questo comportamento usando hint . Citazione:
I suggerimenti sono opzioni o strategie specificate per l'applicazione dall'elaboratore di query di SQL Server sulle istruzioni SELECT, INSERT, UPDATE o DELETE. I suggerimenti sovrascrivono qualsiasi piano di esecuzione che Query Optimizer potrebbe selezionare per una query.
E ancora:
Attenzione:
Poiché l'ottimizzatore di query di SQL Server in genere seleziona il miglior piano di esecuzione per una query, si consiglia & Lt; join_hint > ;, < query_hint > ;, e < table_hint gt &; essere utilizzato solo come ultima risorsa da sviluppatori esperti e amministratori di database.
Altri suggerimenti
Prova " riformattando " la query come segue:
SELECT *
FROM (
SELECT JobQuestion.Value,
Price.Min,
Price.Max,
Price.Amount
FROM Price
INNER
JOIN JobQuestion
ON Price.QuestionFK = JobQuestion.QuestionFK
AND JobQuestion.JobFK = 1
) SQ
WHERE SQ.Min <= SQ.Value
AND SQ.Max >= SQ.Value
Secondo la risposta di Christian Hayter, se hai la scelta, cambia il design della tabella =)
Non dovresti confrontare le stringhe con gli ints. Se hai qualche influenza su tutto il design della tabella, quindi dividi i due diversi usi della colonna JobQuestion.Value
in due colonne diverse.
Nel caso in cui non abbia alcuna influenza sul design della tabella - Potresti provare a filtrare quei record con valori numerici usando ISNUMERIC ()? Immagino che aggiungere questo alla tua clausola where possa aiutare.
Probabilmente puoi rimuovere il dove ... e semplicemente aggiungerli come predicati al tuo join. Dato che è un join interno, questo dovrebbe funzionare
SELECT JobQuestion.Value, Price.Min, Price.Max, Price.Amount
FROM Price
INNER JOIN JobQuestion
ON Price.QuestionFK=JobQuestion.QuestionFK
AND JobQuestion.JobFK=1
AND Price.Min <= JobQuestion.Value
AND Price.Max >= JobQuestion.Value
Puoi usare TRY_PARSE su quelle colonne di stringhe per convertire in valori numerici e, se SQL non è in grado di convertire, otterrai NULL anziché un messaggio di errore.
P.S. Questa cosa è stata introdotta per la prima volta in SQL 2012, quindi potrebbe essere utile.