如何在不指定列名的情况下插入?

时间:2015-02-07 16:06:07

标签: sql sql-server tsql dynamic

拥有多个表格(例如两个):

|PEOPLE_ID|PEOPLE_NAME|PEOPLE_ACCOUNT|OTHER_NULLABLE_COLUMNS|
|001      |"Andrea"   |NULL          |OTHER_NULLABLE_COLUMNS|
|002      |"..."      |NULL          |OTHER_NULLABLE_COLUMNS|

|PET_ID|PET_NAME|PET_OWNER|OTHER_NULLABLE_COLUMNS|
|001   |"Fido"  |NULL     |OTHER_NULLABLE_COLUMNS|
|002   |"..."   |NULL     |OTHER_NULLABLE_COLUMNS|

然后我需要一个通用存储过程来插入任何传递表名(pet,people)以及id和name作为参数的表。

exec sp_inserttottable 'people', '456', 'Gustavo'
exec sp_inserttottable 'pet', '852', 'Scooby'

但是在存储过程的定义中我不能这样做:

CREATE PROCEDURE sp_inserttottable
    @tableName nvarchar(50),
    @codeToInsert nvarchar(4),
    @detailToInsert nvarchar(100)
AS 
    DECLARE @cmd AS NVARCHAR(max)
    SET @cmd = 'INSERT INTO ' + @tableName + ' VALUES(' + @codeToInsert + ',' + @detailToInsert + ' )' + ' '
    EXEC sp_executesql @cmd

它给我一个错误,我需要像这样指定列名:

'INSERT INTO ' + @tableNames + ' (PEOPLE_ID, PEOPLE_NAME) VALUES(' + @codeToInsert + ',' + @detailToInsert + ' )' + ' '

但如果我这样做,程序就不能通用了。

如果我可以这样做,按列顺序放置值

'INSERT INTO ' + @tableNames + ' (1, 2) VALUES(' + @codeToInsert + ',' + @detailToInsert + ' )' + ' '

如何实现这一目标?

(更新)应用@Gordon Linoff的解决方案


首先使用DEFAULT KEYWORD

CREATE PROCEDURE sp_InsertTableType
    @tableNames nvarchar(50),
    @codeToInsert nvarchar(4),
    @detailToInsert nvarchar(100)
AS 
    DECLARE @cmd AS NVARCHAR(max)
    SET @cmd = 'INSERT INTO ' + @tableNames + ' VALUES(' + @codeToInsert + ',' + @detailToInsert + ', DEFAULT)' + ' ';
    --SET @cmd = 'INSERT INTO TTCODI_NACI_UPDATE(CODE, DESCRI) VALUES(' + @codeToInsert + ',' + @detailToInsert + ')' + ' '
    EXEC sp_executesql @cmd

然后我打电话:

exec sp_InsertTableType 'TTCODI_NACI', '1000', 'kuwaiti'

它引发了我:Invalid column name '%.*ls'.

First


第二种选择:

创建视图:

create view TTCODI_NACI_UPDATE
as
    SELECT CO_NACI AS CODE, DE_NACI AS DESCRI
    , DE_ABRE_NACI AS ABRE
    FROM TTCODI_NACI;

更改存储过程:

CREATE PROCEDURE sp_InsertTableType
    @tableNames nvarchar(50),
    @codeToInsert nvarchar(4),
    @detailToInsert nvarchar(100)
AS 
    DECLARE @cmd AS NVARCHAR(max)
    --SET @cmd = 'INSERT INTO ' + @tableNames + ' VALUES(' + @codeToInsert + ',' + @detailToInsert + ', DEFAULT)' + ' ';
    SET @cmd = 'INSERT INTO TTCODI_NACI_UPDATE(CODE, DESCRI) VALUES('
    + @codeToInsert + ',' + @detailToInsert + ')' + ' '
    EXEC sp_executesql @cmd

我打电话的时候:

exec sp_InsertTableType 'TTCODI_NACI', '1000', 'kuwaiti'

它引发了我:Update or insert of view or function '%.*ls' failed because it contains a derived or constant field.

Second Alternative

1 个答案:

答案 0 :(得分:3)

这是解决您问题的方法,但我并不是真的提倡它。你的表是针对不同的实体的,所以我不太确定通用存储过程是个好主意。

一种解决方案是使用DEFAULT关键字:

SET @cmd = 'INSERT INTO ' + @tableName + ' VALUES(DEFAULT, ' + @codeToInsert + ',' + @detailToInsert + ' )' + ' ';

哦,我真的不喜欢那样。这意味着插入取决于列在表中定义的顺序 - 并且对于添加新列并弄乱此代码的任何人都有祸害,远离新列的创建。

我更熟悉的另一个解决方案是创建视图,例如:

create v_people_for_update as
    select people_id as id, people_name as name, people_account as account
    from people;

然后,插入视图:

    SET @cmd = 'INSERT INTO ' + @viewName(name, account) + ' VALUES(, ' + @codeToInsert + ',' + @detailToInsert + ' )' + ' ';

这至少可以让你指定列(一件好事),并且可以命名视图集合,因此很明显这个存储过程正在处理它们。

但是,如果您有具有类似结构的表,那么您应该将它们组合到一个表中,并且不要使用动态SQL在不同表中进行选择。只需使用一个表并添加一列,指定每行引用的事物的类型。