2013-06-15 23 views
7

Próbowałem zaktualizować procedurę przechowywaną, która działała poprawnie bez konieczności użycia sp_executesql. Teraz chcę mieć nazwę tabeli jako parametr, ponieważ mam wiele tabel o tej samej strukturze i nie chcę tworzyć nowych procedur przechowywanych dla każdego z nich.Procedura przechowywana z nazwą tabeli jako parametrem między innymi

Problem polega na tym, że ta wersja wydaje się wymagać wszystkich parametrów, podczas gdy poprzednia akceptowała dowolną liczbę parametrów. Na przykład, jeśli usunę wszystkie parametry WHERE i po prostu ustawię parametr @TableName, to działa dobrze. Próbowałem szukać przykładu, ale nie mogę znaleźć czegoś takiego. Wszystkie przykłady parsowania nazwy tabeli mają tylko ten parametr.

CREATE PROCEDURE cafgTenantNamesTEST2 
    @TableName sysname, 
    @Square nvarchar(100) = null, 
    @Location nvarchar(100) = null, 
    @Name nvarchar(100) = null, 
    @NormalizedName nvarchar(100) = null, 
    @SharedLand int = 0, 
    @FieldNumber int = 0, 
    @Description nvarchar(255) = null, 
    @Dwelling nvarchar(100) = null 
AS 
BEGIN 
    DECLARE @sql AS NVARCHAR(MAX) 
    SET @sql = 'SELECT * FROM [' + @TableName + ']' + 
    'WHERE ([Square] LIKE ''' + @Square + ''' OR ''' + @Square + ''' IS NULL)' + 
    'AND ([Location] = ''' + @Location + ''' OR ''' + @Location + ''' IS NULL)' + 
    ... 
    ... 
--PRINT @sql 
EXEC sp_executesql @sql 
END 

Sugestie proszę.

+0

Sprawdź wartość atrybutu @sql i upewnij się, że można go uruchomić. Czy możesz zbudować ciąg sql, kodując nazwę tabeli i uruchamiając klauzulę Where? – JeffO

+3

Spróbuj dodać spację przed wyrazami "WHERE" i "AND", które łączą się bez białych znaków. – HABO

Odpowiedz

10

Sugestia 1: Użyj QUOTENAME(), aby obsłużyć prawidłowy sposób uniknięcia nazwy tabeli.

Sugestia 2: Wstawiasz wartość parametru do @sql. Nie rób tego. Zamiast tego należy użyć spameterized sql.

Sugestia 3: Wyeliminuj logikę OR, warunkowo tworząc klauzulę WHERE zapytania.

CREATE PROCEDURE cafgTenantNamesTEST2 
    @TableName sysname, 
    @Square nvarchar(100) = null, 
    @Location nvarchar(100) = null, 
    @Name nvarchar(100) = null, 
    @NormalizedName nvarchar(100) = null, 
    @SharedLand int = 0, 
    @FieldNumber int = 0, 
    @Description nvarchar(255) = null, 
    @Dwelling nvarchar(100) = null 
AS 
BEGIN 
    DECLARE @sql AS NVARCHAR(MAX) 
    SET @sql = N'SELECT * FROM ' + QUOTENAME(@TableName) + 
    ' WHERE 1=1 ' 
    IF @Square IS NOT NULL 
     SET @sql = @sql + ' AND ([Square] LIKE @Square)' -- still patameterized 
    IF @Location IS NOT NULL 
     SET @sql = @sql + N' AND ([Location] = @Loc)' 
    ... 
    ... 
--PRINT @sql 
EXEC sp_executesql @sql, N'@Square nvarchar(100), @Loc nvarchar(100)...', @[email protected], @[email protected] -- the param names can be the same or different, sp_executesql has it's own scope. 
END 

Sp_executesql może wykonać sparametryzowany sql oprócz zwykłego sql. Jest to podstawowa procedura składowana systemu używana przez biblioteki klienta do wykonywania sparametryzowanego kodu. Na przykład: System.Data.SqlClient.SqlCommand wywoła sp_executesql, jeśli dodano jakiekolwiek parametry. Jest nietypowy, ponieważ akceptuje zmienną liczbę parametrów. Dokumenty msdn na temat sp_executesql dostarczają pewnych dobrych informacji, ale nie są jasne. Przechwytywanie aktywności w programie SQL profiler jest najprostszym sposobem zobaczenia sp_executesql w akcji.

+0

Brilliant. Dzięki za to @StrayCatDBA. Używam zwykłego sql od lat, ale dopiero zacząłem używać SP i nadal mam z nimi problemy. Będę pracował nad tym jutro teraz, ponieważ jestem dzisiaj związany. Czy za pomocą tej metody mogę założyć, że mogę włączyć dowolną liczbę parametrów podczas wywoływania tego procesu? –

+0

Przepraszam, czy mógłbyś również wyjaśnić linię EXEC? To znaczy. dlaczego deklaracje. –

+0

To działało, dziękuję. Z wyjątkiem, wciąż nie mogę zobaczyć, co robi linia exec, jakbym zawarłem w niej parametry, otrzymuję komunikat o błędzie: _Procedure oczekuje parametru '@parameters' typu 'ntext/nchar/nvarchar'_. –