Cara membuat kueri TSQL Dinamis dengan Pernyataan Mulai dan Akhir

Oke, saya bukan ahli SQL atau DBA, jadi jika ada cara yang lebih baik untuk melakukan ini, silakan angkat bicara.

Namun yang perlu saya lakukan secara khusus adalah meningkatkan Stored Procedure yang sudah ada yang menggunakan SQL dinamis untuk tidak memasukkan nilai duplikat. SQL sendiri ketika spesifik untuk satu tabel adalah hal yang mudah. Namun saat ini, saya mengalami masalah dengan proses tersimpan generik yang saya miliki yang berfungsi secara umum untuk beberapa tabel dan menggunakan TSQL. Masalahnya ada pada pernyataan BEGIN dan END.

    SET @Query =  'IF NOT EXISTS (SELECT ' + @DescriptionFieldName + ' 
       FROM '+ @TableName +'
       WHERE (' + @DescriptionFieldName + ' = ''' + @DescriptionValue + ''') 

    BEGIN
        INSERT INTO '+ @TableName +' (' + @DescriptionFieldName + ', LastUser, LastUpdate) VALUES ('''+ ISNULL(@DescriptionValue, '') +''', '''+ ISNULL(@LastUser, '') +''',Convert(Varchar, GetDate())) '  + 'SELECT CAST(scope_identity() AS int);
    END'

EXEC (@Query)

Ketika saya mengubah EXEC menjadi PRINT, semuanya tampak baik secara sintaksis, tetapi memberikan kesalahan berikut saat menggunakan EXEC:

"Sintaks salah di dekat kata kunci 'BEGIN'."

Adakah yang punya ide tentang cara memperbaiki masalah ini sehingga kueri dapat berfungsi?

Terima kasih!


person atconway    schedule 01.02.2011    source sumber


Jawaban (2)


Sepertinya ada tanda kurung yang hilang setelah klausa Where.

 SET @Query =  'IF NOT EXISTS (SELECT ' + @DescriptionFieldName + ' 
       FROM '+ @TableName +'
       WHERE (' + @DescriptionFieldName + ' = ' + @DescriptionValue + ') )

    BEGIN
        INSERT INTO '+ @TableName +' (' + @DescriptionFieldName + ', LastUser, LastUpdate) VALUES ('''+ ISNULL(@DescriptionValue, '') +''', '''+ ISNULL(@LastUser, '') +''',Convert(Varchar, GetDate())) '  + 'SELECT CAST(scope_identity() AS int);
    END'
person Matthew Manela    schedule 01.02.2011
comment
Ya, tangkapan yang bagus - tidak ada hubungannya dengan BEGIN dan END. Saya juga harus menambahkan (3) tanda tic di sekitar @DescriptionValue (posting asli yang dimodifikasi untuk pembaca selanjutnya) karena varchar seperti ini: WHERE (' + @DescriptionFieldName + ' = ''' + @DescriptionValue + ''')). Apakah metode (3) tic adalah cara terbaik untuk melakukannya? - person atconway; 01.02.2011

FWIW, ketika berhadapan dengan SQL dinamis on-the-fly untuk produksi atau pembuatan kode, saya suka menggunakan templat yang membuatnya sedikit lebih mudah untuk dipelihara (perhatikan bahwa Anda dapat menyematkan jeda baris, yang juga bagus - jangan lupa memasukkan CHAR (13)/CHAR(10) atau perlu spasi sebelum kutipan):

DECLARE @template AS varchar(max) = '
    IF NOT EXISTS (
        SELECT {@DescriptionFieldName} -- Note this is unnecessary
        FROM {@TableName}
        WHERE ({@DescriptionFieldName} = ''{@DescriptionValue}''
    ) 
    BEGIN
        INSERT INTO {@TableName} ({@DescriptionFieldName}, LastUser, LastUpdate)
        VALUES (''{@DescriptionValue}'', ''{@LastUser}'', ''{@LastUpdate}'');
    END
'

DECLARE @Query AS varchar(max) = @template
SET @Query = REPLACE(@Query, '{@DescriptionFieldName}', @DescriptionFieldName)
SET @Query = REPLACE(@Query, '{@TableName}', @TableName)
SET @Query = REPLACE(@Query, '{@DescriptionValue}', ISNULL(@DescriptionValue, ''))
SET @Query = REPLACE(@Query, '{@LastUser}', ISNULL(@LastUser, ''))
SET @Query = REPLACE(@Query, '{@LastUpdate}', @LastUpdate)

PRINT @Query
EXEC (@Query)

Anda masih memiliki tanda kutip ganda, tetapi Anda tidak perlu menambahkan string, ini terlihat jelas ketika Anda lupa mengganti parameter, dan Anda tidak mengulangi penyisipan kode ketika ada sesuatu yang harus berubah.

Perhatikan juga bahwa ini mungkin ada masalah dengan NULL di @DescriptionValue (asli Anda memiliki masalah yang sama di bagian WHERE di EXISTS)

Perhatikan bahwa Anda juga dapat menyusun pengganti Anda dan dengan format yang sesuai, bahkan dapat dibaca:

DECLARE @Query AS varchar(max) = @template
SET @Query = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@Query
                 ,'{@DescriptionFieldName}', @DescriptionFieldName)
                 ,'{@TableName}', @TableName)
                 ,'{@DescriptionValue}', ISNULL(@DescriptionValue, ''))
                 ,'{@LastUser}', ISNULL(@LastUser, ''))
                 ,'{@LastUpdate}', @LastUpdate)
person Cade Roux    schedule 01.02.2011
comment
sangat bagus Saya suka metode ini sebagai 'perbaikan' dari TSQL asli saya. Terima kasih telah berbicara dan menunjukkan ini. - person atconway; 01.02.2011
comment
BTW, ketika Anda menyebutkan SELECT {@DescriptionFieldName} -- Perhatikan bahwa ini tidak perlu, saya mendapatkan: Sintaks yang salah di dekat kata kunci 'FROM'.. Saya tidak bisa hanya SELECT tanpa setidaknya 1 bidang kan? Apa yang akan Anda masukkan? - person atconway; 01.02.2011
comment
@atconway Anda cukup melakukan SELECT * (bukan larangan umum untuk menggunakan SELECT * dalam EXISTS seperti pada SELECT normal) atau SELECT 1. Artinya tidak perlu melakukan penyisipan variabel apa pun. - person Cade Roux; 01.02.2011
comment
@atconway Anda juga dapat menyusun REPLACE Anda - saya tidak melakukannya agar mudah dibaca dalam contoh ini. - person Cade Roux; 01.02.2011