Dynami c SQL (T- SQL) вставить в (имя таблицы Dynami c) с помощью хранимой процедуры (sp_execute sql @ sql) - PullRequest
0 голосов
/ 25 марта 2020

Я борюсь с хранимой процедурой вставки значений в таблицу.

Имя таблицы является переменной, например, Log1

Эта таблица содержит следующие столбцы: Actual, Regulated, Supply, Expected, ControlValue все типы float.

Хранимая процедура имеет те же входные параметры и в дополнение к этому имя таблицы offcource.

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO    

ALTER PROCEDURE [dbo].[InsertIntoTable](
   @TableName nvarchar(50),
   @Actual real,
   @Regulated real,
   @Supply real,
   @Expected real,
   @Control_Value real)
AS
BEGIN 
  SET NOCOUNT ON; 
  DECLARE @columnList varchar(75)
  DECLARE @SQL NVARCHAR(MAX) -- dynamic SQL should always be Unicode

  SET @SQL = N'INSERT INTO dbo.' + @TableName +  '([Actual],[Regulated],[Supply],[Expected],[Control_Value])
        VALUES('+@Actual+','+@Regulated+', '+@Supply+','+@Expected+','+@Control_Value+')'  

  EXEC sp_executesql @sql    
END  

Ответы [ 2 ]

3 голосов
/ 25 марта 2020

Во-первых, тот факт, что вам нужно прибегнуть к динамическому c SQL, указывает на серьезную проблему проектирования базы данных: у вас есть несколько таблиц, в которых хранится одна и та же сущность с некоторыми идентификаторами в имени таблицы.
Принимая ваш Например, если у вас есть таблицы с именами log1, log2 ... logn, вы должны заменить их одной таблицей с именем log и иметь этот номер в качестве другого столбца в этой таблице.

Сказав это, я понимаю, что во многих случаях изменение структуры базы данных не вариант - и по этой причине я покажу вам обходной путь для вашей проблемы (кроме изменения структуры базы данных определение обходного пути, а не решения).

Первое, что вы хотите сделать, это использовать sysname в качестве типа данных для имени таблицы вместо текущего nvarchar(50).
sysname это тип данных, используемый внутренне SQL Сервером для всех идентификаторов.

Второе, что вам нужно, - убедиться, что таблица действительно существует и в ней есть ожидаемые столбцы. Это легко сделать с помощью встроенного системного представления information_schema.columns.

Далее вы хотите обработать свои параметры как параметры - не объединять их в динамическую строку c SQL, а передавать их в качестве параметров для sp_executeSql.

И, наконец, вы хотите защитить от фанки символов в имени таблицы, поэтому вы используете QUOTENAME при объединении его с SQL:

ALTER PROCEDURE [dbo].[InsertIntoTable](
   @TableName sysname,
   @Actual real,
   @Regulated real,
   @Supply real,
   @Expected real,
   @Control_Value real)
AS
BEGIN 
  SET NOCOUNT ON; 

  DECLARE @ColumnCount int;
  SELECT @ColumnCount = COUNT(*)
  FROM Information_schema.Columns
  WHERE Table_Name = @TableName
  AND COLUMN_NAME IN([Actual],[Regulated],[Supply],[Expected],[Control_Value])

  IF @ColumnCount < 5 RETURN;


  DECLARE @SQL NVARCHAR(MAX) -- dynamic SQL should always be Unicode

  SET @SQL = N'INSERT INTO dbo.' + QUOTENAME(@TableName) +  '([Actual],[Regulated],[Supply],[Expected],[Control_Value])
        VALUES(@Actual, @Regulated, @Supply, @Expected, @Control_Value)'  

  EXEC sp_executesql 
      @sql, 
      N'@Actual real, @Regulated real, @Supply real, @Expected real, @Control_Value real',
      @Actual, @Regulated, @Supply, @Expected, @Control_Value
END 

Для более подробного объяснения, посмотрите мой пост в блоге под названием Что нужно и чего не нужно делать динамически c SQL для SQL Сервер .

2 голосов
/ 25 марта 2020

Правильно сгенерируйте динамический оператор c и выполните sp_executesql с использованием параметров. Вероятно, ваша фактическая ошибка Error converting data type nvarchar to real., потому что вы пытаетесь объединить текст (N'INSERT INTO ... VALUES(') и числа (@Regulated, @Supply, ...). Конечно, внимательно подумайте, что @ZoharPeled объяснил в своем ответе.

ALTER PROCEDURE [dbo].[InsertIntoTable](
   @TableName nvarchar(50),
   @Actual real,
   @Regulated real,
   @Supply real,
   @Expected real,
   @Control_Value real)
AS
BEGIN 
    SET NOCOUNT ON

    DECLARE @err int
    DECLARE @sql nvarchar(max)

    SET @sql = 
        N'INSERT INTO dbo.' + QUOTENAME(@TableName) + ' ([Actual],[Regulated],[Supply],[Expected],[Control_Value]) '+
        N'VALUES (@Actual, @Regulated, @Supply, @Expected, @Control_Value)'  

    EXEC @err = sp_executesql 
        @sql, 
        N'@Actual real, @Regulated real, @Supply real, @Expected real, @Control_Value real',
        @Actual, @Regulated, @Supply, @Expected, @Control_Value

    RETURN @err 
END  
...