插入具有Identity和timestamp的SQL Server表的正确SQL语句是什么

时间:2014-07-07 20:31:12

标签: sql sql-server vb.net

我有一张桌子......

if exists (select * from dbo.sysobjects 
           where id = object_id(N'[dbo].[ADDRESS_BOOK]') 
             and OBJECTPROPERTY(id, N'IsUserTable') = 1)
    drop table [dbo].[ADDRESS_BOOK]
GO

CREATE TABLE [dbo].[ADDRESS_BOOK] 
(
   [ID] [bigint] IDENTITY (1, 1) NOT NULL ,
   [FIRST_NAME] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
   [LAST_NAME] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
   [CONTACT_NOS] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
   [MODIFIED_BY] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
   [MODIFIED_TIME] [timestamp] NULL 
) ON [PRIMARY]
GO

我的问题是将数据插入此表的SQL语句应该是什么?

我试过

        Dim sb As New StringBuilder
        With sb
            .Append("SET IDENTITY_INSERT ADDRESS_BOOK ON ")
            .Append("INSERT INTO ADDRESS_BOOK(ID,FIRST_NAME,LAST_NAME,")
            .Append("CONTACT_NOS,MODIFIED_BY,MODIFIED_TIME) VALUES(NULL,")
            .Append("'" & TbFName.Text & "','" & TbLName.Text & "','" & TbContactNos.text & "','" & TbUser.Text & "',NULL)")
            .Append(" SET IDENTITY_INSERT ADDRESS_BOOK OFF")
        End With
        Dim cmd As New SqlCommand
        cmd.Connection = conn
        cmd.CommandText = sb.ToString
        cmd.ExecuteNonQuery()

但它给了我错误......

Cannot insert the value NULL into column 'ID', table 'MY_DB.dbo.ADDRESS_BOOK'; column does not allow nulls. INSERT fails. The statement has been terminated.

4 个答案:

答案 0 :(得分:3)

这一行:

.Append("CONTACT_NOS,MODIFIED_BY,MODIFIED_TIME) VALUES(NULL,")

您正试图在不接受NULL的列中插入NULLS

ID列设置为自动增量(IDENTITY (1,1))。

只需将该列从查询参数中删除(它将自动递增),您的查询应该没问题。

建议:使用参数化查询。它是一种更清晰,更优化的查询数据库的方式。它有很多优点(你可以自己阅读,我在这里不会对它们有所了解)。

此外,您不需要在每一行都使用追加。它只是糟糕的编码和非常恼人的阅读!此外,像这样的代码极不可能通过任何一轮的代码审查。

<强> 编辑:

   INSERT INTO ADDRESS_BOOK(FIRST_NAME, LAST_NAME, CONTACT_NOS, MODIFIED_BY, MODIFIED_TIME)  VALUES('FirstName', 'LastName', '1234567890', 'SomeName', '2014-01-01 12:15:17.227')

请注意,我在这里根本没有提到专栏ID。执行此语句时,包含此行的表将自动具有ID值。

希望这有帮助!!!

答案 1 :(得分:2)

这里有一个以上的问题。 timestamp数据类型(aka rowversion)不是datetime数据类型。请在这里阅读。 http://technet.microsoft.com/en-us/library/ms182776.aspx

其次,正如其他人已经指出你的代码对sql注入是开放的。你真的应该为这类事情使用存储过程。

以下是我将如何编写此内容,包括具有正确数据类型的ddl。

CREATE TABLE [dbo].[ADDRESS_BOOK] 
(
   [ID] [bigint] IDENTITY (1, 1) NOT NULL ,
   [FIRST_NAME] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
   [LAST_NAME] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
   [CONTACT_NOS] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
   [MODIFIED_BY] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
   [MODIFIED_TIME] [timestamp] NULL 
) ON [PRIMARY]
GO

create procedure Address_Book_Insert
(
    @FName varchar(10)
    , @LName varchar(10)
    , @Contact_NOS varchar(50)
    , @Modified_By varchar(20)
    , @Modified_Time datetime
) as
    INSERT ADDRESS_BOOK
    (
        FIRST_NAME
        , LAST_NAME
        , CONTACT_NOS
        , MODIFIED_BY
        , MODIFIED_TIME
    )
    VALUES
    (
        @FName
        , @LName
        , @Contact_NOS
        , @Modified_By
        , @Modified_Time
    )

go

然后这很简单。您更改代码以使用存储过程,建立参数并执行存储过程。您可以轻松分离逻辑和数据,您的代码将更安全,并且维护起来更容易。

答案 2 :(得分:0)

不要使用SQL注入,很容易破坏你的程序。 另外,不要为ID发送空值,请确保使用IDENTITY(1,1)自动增量 我建议你使用存储过程做什么......就像这样:


ON SQL:

CREATE PROCEDURE '<schemaname>.InsertOnAddressBook'
(
--this is the arguments/parameters you should pass to the stored procedure
@TbFName varchar(30), --remember, this limit of varchar can be changed as you wish
@TbLName varchar(30),
@TbContactNos varchar(30),
@TbUser varchar(20)
)

AS

BEGIN
SET IDENTITY_INSERT ADDRESS_BOOK ON
INSERT INTO ADDRESS_BOOK
(FIRST_NAME,LAST_NAME,CONTACT_NOS,MODIFIED_BY,MODIFIED_TIME) 
VALUES(@TbFName, @TbLName, @TbContactNos, @TbUser, NULL) 

SET IDENTITY_INSERT ADDRESS_BOOK OFF
END

ON VB.NET SIDE:

cmd.CommandText = "<schemaname>.InsertOnAddressBook"
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("@TbFName",TbFName.text)
cmd.Parameters.AddWithValue("@TbLName",TbLName.text)
cmd.Parameters.AddWithValue("@TbContactNos",TbContactNos.text)
cmd.Parameters.AddWithValue("@TbUser",TbUser.text)

安全性方面,从后面的代码执行存储过程更加安全!

答案 3 :(得分:0)

如果IDENTITY_INSERT设置为ON,那么我们必须为Explicit value列指定IDENTITY。否则会出现错误

  

当IDENTITY_INSERT设置为ON时,必须为表'TableName'中的标识列指定显式值。

另一方面:

  

只需将该列从查询参数中删除(它将自动递增),您的查询应该没问题。

从@Satwik Nadkarny实施上述声明,我找到了答案。

<强> SOLUTION:

Dim sb As New StringBuilder
With sb
    '.Append("SET IDENTITY_INSERT ADDRESS_BOOK ON ") '<-- No need to set it ON if we do not specify the Explicit value.
     .Append("INSERT INTO ADDRESS_BOOK(FIRST_NAME,LAST_NAME,") '<-- I leaved the ID column out of the query
     .Append("CONTACT_NOS,MODIFIED_BY,MODIFIED_TIME) VALUES(NULL,")
     .Append("'" & TbFName.Text & "','" & TbLName.Text & "','" & TbContactNos.text & "','" & TbUser.Text & "','" & MODIFIED_TIME & "')")
    '.Append(" SET IDENTITY_INSERT ADDRESS_BOOK OFF") '<-- No need to set it OFF
End With
    Dim cmd As New SqlCommand
    cmd.Connection = conn
    cmd.CommandText = sb.ToString
    cmd.ExecuteNonQuery()

<强> SQL:

"INSERT INTO TABLE_NAME(FIELD2,FIELD3,FIELD4) VALUES(FIELD2_DATA,FIELD3_DATA,FIELD4_DATA)"

在上面的SQL查询语句中,FIELD1ID自动增量标识(1,1)字段,我将其从查询中排除。此外,我必须学习查询参数化,因为我从未使用过它。


最后,我知道为什么我被投票支持会很有帮助。

感谢@Satwik的想法。它对我帮助很大。