子查询返回的值超过1。这是不允许的

时间:2012-05-18 18:36:53

标签: sql-server triggers

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

日Thnx

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)

5 个答案:

答案 0 :(得分: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上定义的触发器中。我没有在发布的代码中看到任何会抛出子查询异常的内容。

触发器(也称为地雷)插入到已在其上定义触发器的表中是一种痛苦的处方。如果可能的话,尝试将一些逻辑从触发器重构为逻辑上遵循的代码。

答案 1 :(得分:2)

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

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

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

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

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

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

答案 2 :(得分:1)

你有一个包含声明的触发器:

SELECT @customerid = id FROM inserted

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

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

答案 3 :(得分:-1)

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

如果需要多个,则重构查询,使表成为主查询的一部分。

我举的SQL示例: 从table1中选择col1,(从table2中选择col2,其中table2.col3 = table1.col4); 如果col2返回多行,则查询失败,然后将其重新写入:

从table1,table2中选择col1,col2,其中table2.col3 = table1.col4;

我希望你明白这一点。

答案 4 :(得分:-3)

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

SET @maxid = MAX(ID) FROM another_table