2016-06-16 9 views
8

Biorąc poniższej tabeli:Konkatenowanie INT i VARCHAR wewnątrz EXEC nie produkuje błąd konwersji

USE tempdb; 

CREATE TABLE #T(Val INT); 
INSERT INTO #T VALUES (1), (2), (3), (4), (5); 

Chciałem wykonać dynamiczne zapytanie SQL za pomocą EXEC otrzymał Val wartość:

DECLARE @sql NVARCHAR(MAX); 
DECLARE @Val INT = 3; 

EXEC ('SELECT * FROM #T WHERE Val = ' + @Val); 

to wykonuje bez błąd i daje prawidłowy wynik.

Moim założeniem jest to, że będzie produkować błąd:

Conversion failed when converting the varchar value 'SELECT * FROM #T WHERE Val = ' to data type int.

Od @Val jest INT typu danych oraz zasad data type precedence kwerenda wewnątrz EXEC muszą być zamienione na INT.

Moje pytanie brzmi: dlaczego połączenie z numerem EXEC nie spowodowało błędu konwersji?


Uwagi:

- Wiem o sp_executesql. Nie pytam też o alternatywę. Po prostu pytam o wyjaśnienie, dlaczego nie powstał błąd.

- Odpowiedź na to question nie wydaje się wyjaśnić moją sytuację jako kwestia odnosi się do VARCHARVARCHAR konkatenacji.

+3

Ja * wierzę *, że jest to trzymanie w złych czasach. Nawet z powrotem na przykład SQL Server 2000, można "EXEC" z wieloma ciągami znaków '+ 'ed, które przekroczyłyby granice znaków 8000/4000 dla varchar/nvarchar w tym czasie. Dlatego uważam, że '+' wewnątrz 'EXEC()' jest * nie * standardowym operatorem konkatenacji ciągów. Mimo że funkcja jest określona tylko do akceptowania typów danych łańcuchowych, domyślam się, że oznacza to, że będzie sznurować wszelkie typy nie-łańcuchowe, a pierwszeństwo danych może zejść z krótkiego pomostu. Ale to tylko spekulacja, a więc nie odpowiedź. –

+1

Podobne pytanie zostało zadane wcześniej: http://stackoverflow.com/questions/26135174/type-conversion-in-exec-statement – Alex

+2

@Damien_The_Unbeliever, masz bardzo interesującą teorię, jedna obserwacja: poniższe nie działa : EXEC ("SELECT" + 3), ale konkatenacja z użyciem zmiennej 'INT' działa. – Alex

Odpowiedz

6

Według MSDN/BOL, uproszczona składnia EXEC[UTE] jest stwierdzenie:

Execute a character string 
{ EXEC | EXECUTE } 
    ({ @string_variable | [ N ]'tsql_string' } [ + ...n ]) 
    [ AS { USER } = ' name ' ] 
[;] 

@string_variable 
Is the name of a local variable. @string_variable can be any char, varchar, nchar, or nvarchar data type. These include the (max) data types. 

Kilka uwag:

1) Zgodnie z tą linią ({ @string_variable | [ N ] 'command_string [ ? ]' } [ **+** ...n ], możemy napisać coś takiego EXEC (@var1 + @var2 + @var3) ale według ostatniego ust SQL Serwer oczekuje, że te zmienne będą mieć jedną z następujących wartości: string typ danych: char, varchar, nchar lub nvarchar.

2) Ta składnia odnosi się tylko do: string variables (@string_variable | [ N ] 'command_string [ ? ]' } [ + ...n). Uważam, że jest to powód, dla którego EXEC ('SELECT * FROM #T WHERE Val = ' + 3); nie powiedzie się: 3 nie jest zmienną.

3) Zakładam, że , gdy jedna z tych zmiennych nie ma jednego z powyższych typów łańcuchów, SQL Server wykona niejawną konwersję. Zakładam, że konwertuje ze zmiennej źródłowej z INT (na przykład) na NVARCHAR, ponieważ ma najwyższą wartość data type precedence między tymi typami łańcuchów.

4) To nie jedyne miejsce, w którym data type precedence nie działa. ISNULL(param1, param2) to tylko kolejny przykład. W takim przypadku param2 zostanie przekonwertowany na typ danych param1.

+2

Tak, rzecz po '+' może być tylko ciągiem w gramatyce, więc zostanie zinterpretowana jako ciąg przed konkatenacją. Akceptacja zmiennych, które w rzeczywistości nie są "char", "varchar',' nchar' lub 'nvarchar' nie wydaje się być udokumentowana, więc prawdopodobnie należy tego unikać. –

0

niejawna konwersja z int typów łańcuchowych jest dozwolone, co najmniej tak daleko jak SQL Server 2008.

Ref: Data Type Conversion (Database Engine)

Nie można wyłączyć niejawna konwersja: Is there a way to turn off implicit type conversion in SQL Server?

Edycja : Oryginalnie napisałem:

'SELECT * FROM #T WHERE Val = ' + @Val is created before the call to EXEC .

Nie jestem taki s Mówimy o tym. Teraz podejrzewam, że argument do EXEC jest przekazywany do części silnika bazy danych, który analizuje go w inny sposób niż to, do którego jesteśmy przyzwyczajeni.

+1

Problem nie jest domyślną konwersją, ale priorytetem. 'int' ma priorytet, więc' wybierz 'WYBIERZ * Z # T GDZIE Val =' + @ Val' wyrzuca błąd konwersji varchar na int. Jednak EXEC zachowuje się inaczej –

+0

@PanagiotisKanavos Niemniej jednak musi to być to, co się dzieje. –

0

Wszystko, MSDN powiedzieć o concatinating w EXEC [UTE] jest:

the concatenation is performed logically in the SQL Server parser and never materializes in memory.

Więc nie wiemy dużo o tym, co robi SQL Server głęboko wewnątrz. Wiemy jedynie, że EXEC nie akceptuje wyrażenia jako argumentu, zamiast tego przyjmuje listę ciągów ograniczonych przez "+".

Jeśli spojrzeć na składni:

Execute a character string 
{ EXEC | EXECUTE } 
    ({ @string_variable | [ N ]'tsql_string' } [ + ...n ]) 
    [ AS { LOGIN | USER } = ' name ' ] 
[;] 

ona bezpośrednio obsługuje wiele sznurków lub zmiennych oddzielonych znakiem „+”. Tak więc nie przekazujesz EXECu wyrażenia, a więc omijasz analizator wyrażeń SQL Server.

+0

Ale dlaczego konkatenacja 'int' i' varchar' nie spowodowała błędu? –

Powiązane problemy