-1
ALTER TRIGGER t1
ON dbo.Customers

FOR INSERT
AS

BEGIN TRANSACTION

/* variables */

DECLARE
    @maxid bigint

SELECT @customerid = id FROM inserted

SET IDENTITY_INSERT dbo.new_table ON

DECLARE
    @maxid bigint

SELECT @maxid = MAX(ID) FROM new_table

INSERT INTO new_table (ID, ParentID, Foo, Bar, Buzz)
    SELECT ID+@maxid, ParentID+@maxid, Foo, Bar, Buzz FROM initial_table

SET IDENTITY_INSERT dbo.new_tableOFF

/* execute */
COMMIT TRANSACTION

GO

失败:

SQL Server 子查询返回超过 1 个值。当子查询跟随 =、!=、<、<=、>、>= 或子查询用作表达式时,这是不允许的

如何解决?

我想做的是

  • 插入idparentid,每个增加@maxid
  • initial_table
  • 进入new_table

谢谢

新表

id (bigint) 
parentid (bigint - linked to id) 
foo | bar | buzz (others are nvarchar, not really important)

初始表

id (bigint) 
parentid (bigint - linked to id)
foo | bar | buzz (others are nvarchar, not really important)
4

5 回答 5

3

您正在与我怀疑的一些错误作斗争。

1. 您正在插入违反 new_table 中唯一约束的值。通过加入要插入的表来避免存在错误。调整连接条件以匹配表的约束:

insert into new_table (ID, ParentID, Foo, Bar, Buzz)
    select  ID+@maxid, ParentID+@maxid, Foo, Bar, Buzz 
    from    initial_table i
    left
    join    new_table N on 
            i.ID+@maxid = n.ID or 
            i.ParentID+@maxid = n.ParentId
    where   n.ID is null --make sure its not already there

2. 在某个地方,子查询返回了您期望的多行。子查询错误可能在插入 dbo.Customer 的代码中(触发 t1),或者可能在 new_table 上定义的触发器中。我在发布的代码中看不到任何会引发子查询异常的内容。

将触发器(又名地雷)插入到定义了触发器的表中是一种痛苦的方法。如果可能,请尝试将其中的一些逻辑从触发器中重构为您可以在逻辑上遵循的代码。

于 2012-05-18T18:50:49.160 回答
2

首先,您必须假设插入或删除的记录不止一条。您不应该将插入或删除表中的值设置为 SQL 服务器触发器中的标量变量。如果插入包含多个记录并且迟早会出现问题,则会导致问题。

接下来,您永远不应该考虑在触发器中设置身份插入。你在想什么?如果您有一个身份字段,请使用它,然后不要尝试手动创建一个值。

接下来,子查询问题显然与另一个触发器相关联,您还假设一次只处理一条记录。我怀疑您需要检查数据库中的每个触发器并解决这个基本问题。

现在,当您运行这部分代码时:

INSERT INTO new_table (ID, ParentID, Foo, Bar, Buzz) 
SELECT ID+@maxid, ParentID+@maxid, Foo, Bar, Buzz FROM initial_table 

您正在尝试在表中插入所有记录,而不仅仅是插入的记录。因此,由于您在另一个表上的触发器编写不正确,因此您遇到了一个错误,该错误实际上隐藏了当您尝试将 2000 条具有相同 PK 的记录插入新表时会遇到的错误,或者如果您没有PK,每次插入一条记录时,它都会很乐意将它们全部插入。

于 2012-05-18T19:55:09.573 回答
1

您有一个包含以下语句的触发器:

SELECT @customerid = id FROM inserted

inserted表包含插入(或为UPDATE触发器更新)的每一行的一行。执行的语句插入了多行,触发了触发器,并且您的假设被暴露了。

重新编码触发器以操作行集,而不是单行。

于 2012-05-18T19:52:00.460 回答
-1

在任何类型的选择中使用子查询时,请尝试调整您的查询,以便子查询仅返回 1 个值而不是多个值。

如果需要多个,则以表成为主查询的一部分的方式重组查询。

我给出了 SQL 的例子: Select col1, (select col2 from table2 where table2.col3=table1.col4) from table1; 如果 col2 返回多行,则查询失败,然后将其重写为:

选择 col1, col2 from table1,table2 where table2.col3=table1.col4;

我希望你明白这一点。

于 2012-05-18T18:51:08.457 回答
-3

你不应该选择它,你应该设置它。

SET @maxid = MAX(ID) FROM another_table 
于 2012-05-18T18:45:50.660 回答