将数据插入存储过程中的不同表中

时间:2014-01-02 23:24:53

标签: sql-server tsql stored-procedures insert sql-insert

以下是始终插入table1的原始SP(INSERT INTO table1)。现在我需要插入table1或table2,它们都具有相同的结构。

我尝试将tableName作为参数传递给SP。

ALTER PROCEDURE [dbo].[sp_importStats] (
@accountID BIGINT,  
@csvFileName VARCHAR (1024),
@csvFormatFileName VARCHAR (1024)
@tableName VARCHAR(256))

然后我尝试使用EXECUTE进行INSERT,如下所示:

--Incorrect syntax near EXECUTE.
EXECUTE(    
'INSERT INTO '+ @tableName + '(accountId, date, cost)
(SELECT cte.id, ms.date, ms.cost
FROM #stats ms
INNER JOIN CTE cte ON ms.accountNumber = cte.key4)');

然后我尝试了这个:

--Must declare the table variable @tableName.
INSERT INTO @tableName (accountId, date, cost)
(SELECT cte.id, ms.date, ms.cost
FROM #stats ms
INNER JOIN CTE cte ON ms.accountNumber = cte.key4);

然后我尝试不传递tableName,而是将一个布尔值传递给SP,并根据它决定我需要插入哪个表:

ALTER PROCEDURE [dbo].[sp_importStats] (
@accountID BIGINT,  
@csvFileName VARCHAR (1024),
@csvFormatFileName VARCHAR (1024),
@condition BIT = 0)

IF (@condition= 0)
SET @table = 'table1'
ELSE    
SET @table = 'table2'

--Must declare the table variable "@table".
INSERT INTO @table (accountId, date, cost)
(SELECT cte.id, ms.date, ms.cost
FROM #sats ms
INNER JOIN CTE cte ON ms.accountNumber = cte.key4);

无论哪种方式我都有错误。你能不能让我知道处理这件事的最佳方法是什么?为什么我收到这些错误?非常感谢任何帮助。

原始SP:

ALTER PROCEDURE [dbo].[sp_importStats] (
@accountID BIGINT,  
@csvFileName VARCHAR (1024),
@csvFormatFileName VARCHAR (1024))

AS
BEGIN

CREATE TABLE #stats(
    [accountID]        [bigint]         NOT NULL,
    [accountNumber]    [varchar](30)        NULL,
    [date]             [datetime]       NOT NULL,       
    [cost]             [money]              NULL,       
);

EXECUTE('INSERT INTO #stats SELECT * FROM '+
    'OPENROWSET (BULK N''' + @csvFileName + '''' +      
    ',FORMATFILE='''+@csvFormatFileName+''''+
    ',FIRSTROW=2'+
    ',MAXERRORS=0'+
    ') AS t;');     

WITH CTE(id, key4) AS (
    SELECT  A.id, A.[key4]
    FROM    VA A (NOLOCK)
    WHERE   A.id = @accountID
    UNION ALL
    SELECT  A.id, A.[key4]
    FROM    VA A (NOLOCK)
    INNER JOIN CTE ON (CTE.id = A.MAID)
    WHERE A.key4 IS NOT NULL
)

INSERT INTO table1 (accountId, date, cost)
(SELECT cte.id, ms.date, ms.cost
FROM #stats ms
INNER JOIN CTE cte ON ms.accountNumber = cte.key4);

DROP TABLE #stats;

END

这就是我现在所拥有的:

ALTER PROCEDURE [dbo].[sp_importStats] (
@accountID BIGINT,  
@csvFileName VARCHAR (1024),
@csvFormatFileName VARCHAR (1024)
@tableName VARCHAR(256))

AS
BEGIN

DECLARE @sql NVARCHAR(MAX);

CREATE TABLE #stats(
    [accountID]        [bigint]         NOT NULL,
    [accountNumber]    [varchar](30)        NULL,
    [date]           [datetime]       NOT NULL,     
    [cost]             [money]              NULL,       
);

EXECUTE('INSERT INTO #stats SELECT * FROM '+
    'OPENROWSET (BULK N''' + @csvFileName + '''' +      
    ',FORMATFILE='''+@csvFormatFileName+''''+
    ',FIRSTROW=2'+
    ',MAXERRORS=0'+
    ') AS t;');     

WITH CTE(id, key4) AS (
    SELECT  A.id, A.[key4]
    FROM    VA A (NOLOCK)
    WHERE   A.id = @accountID
    UNION ALL
    SELECT  A.id, A.[key4]
    FROM    VA A (NOLOCK)
    INNER JOIN CTE ON (CTE.id = A.MAID)
    WHERE A.key4 IS NOT NULL
)

--Incorect synstax near SET.
SET @sql = 'INSERT INTO '+ QUOTENAME(@tableName) + '(accountId, date, cost)
(SELECT cte.id, ms.date, ms.cost
FROM #stats ms
INNER JOIN CTE cte ON ms.accountNumber = cte.key4)';

EXECUTE sp_executesql @sql;

DROP TABLE #stats;

END

2 个答案:

答案 0 :(得分:1)

将表名作为参数传递

使用QUOTENAME() Function在表名周围放置方括号,以明确告诉sql server它是一个像这样的Sql Server对象名。

DECLARE @Sql NVARCHAR(MAX);

 SET @Sql = N';WITH CTE(id, key4) AS (
                SELECT  A.id, A.[key4]
                FROM    VA A (NOLOCK)
                WHERE   A.id = @accountID
                UNION ALL
                SELECT  A.id, A.[key4]
                FROM    VA A (NOLOCK)
                INNER JOIN CTE ON (CTE.id = A.MAID)
                WHERE A.key4 IS NOT NULL
            )
            INSERT INTO ' +  QUOTENAME(@tableName) +' (accountId, date, cost)
            SELECT cte.id, ms.date, ms.cost
            FROM #stats ms
            INNER JOIN CTE cte ON ms.accountNumber = cte.key4;'  

EXECUTE sp_executesql @Sql

使用QUOTENAME()函数可以保护您免受sql injection attack的攻击。您也不需要在select语句周围使用括号。

此外,您应该避免为存储过程名称使用sp_前缀。 Read Here为什么。

使用IF..ELSE阻止

IF (Some_Condition IS TRUE)
 BEGIN
   /* Insert Statement For Table One*/  --<-- No need to use table Names as variable
 END                                       -- just hardcode the table names in your
ELSE                                       -- Insert Statements
 BEGIN
   /* Insert Statement For Table Two*/
 END

答案 1 :(得分:0)

您是否注意到您在声明中错过了逗号。

ALTER PROCEDURE [dbo].[sp_importStats] (
@accountID BIGINT,  
@csvFileName VARCHAR (1024),
@csvFormatFileName VARCHAR (1024),---comma missing here
@tableName VARCHAR(256))