为啥我必须在这个插入语句中包含主键列?

Posted

技术标签:

【中文标题】为啥我必须在这个插入语句中包含主键列?【英文标题】:Why do I have to include the primary key column in this insert statement?为什么我必须在这个插入语句中包含主键列? 【发布时间】:2013-01-11 05:36:14 【问题描述】:

给定一个 SQL Server Express Compact Edition 数据库,其中包含一个名为“Clients”的表,其中包含以下列:

ID, FirstName, MiddleName, Nickname, LastName, Suffix, IsMale

其中 ID 是自动递增的主键/标识值,当我尝试在表上使用此命令时:

INSERT INTO Clients (Title, FirstName, MiddleName, Nickname, LastName, Suffix,
IsMale) VALUES ('', 'John', '', '', 'Smith', '', 'True')

一切正常。但是当我尝试使用这个命令时:

INSERT INTO Clients VALUES ('', 'John', '', '', 'Smith', '', 'True')

出现此错误:

The number of columns in the query and the table must match. [ Number of columns
in query = 7, Number of columns in table = 8 ]

我在 SQL Server 中使用插入语句已经有一段时间了,这从来都不是问题;针对列数的验证始终忽略自动递增的主键/身份类型。在这种情况下,唯一的主要区别是我现在使用的是非常低端的 SQL Server 版本,而我习惯使用更专业的版本。万一这可能很重要,我在 C# 程序中使用它。

这是什么原因造成的?谢谢。

编辑:这个问题的很多焦点是我在使用非免费、非紧凑版本的 SQL Server 时从未遇到过这个问题。我以前使用的 SQL Server 总是足够聪明,可以忽略列计数中的标识/主键列,并且只需找出自动递增的值,而无需我拼出特定的列名。

虽然这里的另一个区别是我以前总是使用 SQL Management Studio 来处理表定义,而在这种情况下我正在使用 VS 2012 和 SQL Server Compact Edition。所涉及的用户界面显然非常不同,所以我想可能是为表指定了某些内容,或者当您在 Management Studio 中执行此操作时,可能会阻止此问题发生?

【问题讨论】:

查看(并关注!):Bad habits to kick : using SELECT * / omitting the column list - 在SELECTINSERT 语句中始终明确指定列列表被认为是最佳实践 这个does work。问题一定是别的。 (例如,您的 ID 并不是真正的 IDENTITY,而是由触发器处理。)话虽如此,我同意 @marc_s 的评论。 "我现在使用的是非常低端的 SQL Server 版本,而我习惯使用更专业的版本" - 请详细说明 SQL Server Compact Edition Express,尽管我已经忘记了它的确切名称,但我们倾向于在工作中使用完全成熟的 SQL Server 2012,并配有 SQL Server Management Studio。尽管我不记得确切的名称,但我在这里使用的是精简版的免费版本,而我通常习惯使用非精简版的昂贵版本。我现在不在工作,所以我找不到确切的名字。 这可能是 Compact Edition 特有的(如果这确实是您的服务器版本),但我无法确定。从未使用过精简版,至于我使用过的那些版本,不记得遇到过此类问题。 【参考方案1】:

如果您没有在插入语句中指定列,那么它会考虑所有列。即使其中一列是自动递增的。

Insert - MSDN

column_list 必须在 将显式值插入到 标识列,并且 SET IDENTITY_INSERT 选项必须为 ON 桌子。

【讨论】:

是的,但默认情况下,当您没有提供列列表时,自动增量列被视为与计算列相同,这意味着您必须仅为所有“正常”列指定值。反过来,这意味着 OP 的声明应该起作用 if ID 确实是一个 IDENTITY 列(我目前非常怀疑,否则他们忘记提及的东西)。【参考方案2】:

可以用两种形式编写 INSERT INTO 语句。

第一种形式没有指定将插入数据的列名,只指定它们的值:

INSERT INTO table_name
VALUES (value1, value2, value3,...)

这只有在提供的值的数量与列数完全匹配

时才有效

第二种形式指定了列名和要插入的值:

INSERT INTO table_name (column1, column2, column3,...)
VALUES (value1, value2, value3,...)

这是必须使用的表单,即使有标识类型的 ID 列。

拉吉


【讨论】:

出于某种原因,我总是看到它在使用昂贵的非紧凑版本的 SQL Server / SQL Management Studio 时仍然有效。【参考方案3】:

你忘了提到表Clients 有一个列名Title。第一个查询有效,因为您已经为语句中指定的列显式定义了值。

第二个失败,因为您使用的是Implicit 类型的INSERT 语句。使用该类型的INSERT 时,您必须为表中的所有列指定所有值。由于表中的第一列是ID,并且是Auto_Incremented,所以可以用NULL代替值。

INSERT INTO Clients VALUES (NULL, '', 'John', '', '', 'Smith', '', 'True')

【讨论】:

【参考方案4】:

我认为''代表一个不能插入整数值的空字符串

所以你可以指定 NULL 而不是 ' '

【讨论】:

以上是关于为啥我必须在这个插入语句中包含主键列?的主要内容,如果未能解决你的问题,请参考以下文章

Mybatis 插入insert操作时获取主键

当主键列不是标识列时如何插入数据?

sql主键列自增问题

PHP mySQL - 将新记录插入表中,主键自动递增

sql server 中 怎么让自动增1的主键列 临时的 让它可以手动插入指定值?

如何在 Postgres 中为 UUID 主键列设置默认值?