SQL Server子查询返回了多个值。当子查询遵循=,!=,<,<=,>,> =时,不允许这样做


81

我运行以下查询:

SELECT 
   orderdetails.sku,
   orderdetails.mf_item_number,
   orderdetails.qty,
   orderdetails.price,
   supplier.supplierid,
   supplier.suppliername,
   supplier.dropshipfees,
   cost = (SELECT supplier_item.price
           FROM   supplier_item,
                  orderdetails,
                  supplier
           WHERE  supplier_item.sku = orderdetails.sku
                  AND supplier_item.supplierid = supplier.supplierid)
FROM   orderdetails,
       supplier,
       group_master
WHERE  invoiceid = '339740'
       AND orderdetails.mfr_id = supplier.supplierid
       AND group_master.sku = orderdetails.sku  

我收到以下错误:

消息512,级别16,状态1,第2行子查询返回的值大于1。当子查询遵循=,!=,<,<=,>,> =或将子查询用作表达式时,不允许这样做。

有任何想法吗?


39
哦,不要再使用隐式的join语法了,这是一种非常糟糕的做法,更难于维护并且更容易出错。
HLGEM

1
@HLGEM为什么实践不佳,更难维护且更容易出错?
reggaeguitar '19

5
这些表连接到哪些字段?提示:我无法分辨的事实就是问题所在。
naughtilus

Answers:


48

试试这个:

SELECT
    od.Sku,
    od.mf_item_number,
    od.Qty,
    od.Price,
    s.SupplierId,
    s.SupplierName,
    s.DropShipFees,
    si.Price as cost
FROM
    OrderDetails od
    INNER JOIN Supplier s on s.SupplierId = od.Mfr_ID
    INNER JOIN Group_Master gm on gm.Sku = od.Sku
    INNER JOIN Supplier_Item si on si.SKU = od.Sku and si.SupplierId = s.SupplierID
WHERE
    od.invoiceid = '339740'

这将返回除cost列之外相同的多行。查看返回的不同成本值,并找出导致这些不同值的原因。然后询问某人他们想要哪个成本值,然后将条件添加到查询中以选择该成本。


42

检查要尝试对其执行查询的表上是否有任何触发器。他们有时会在尝试运行表上的更新/选择/插入触发器时抛出此错误。

您可以修改您的查询,以禁用再启用触发若触发DOES NOT需要任何查询,你正在尝试运行被执行。

ALTER TABLE your_table DISABLE TRIGGER [the_trigger_name]

UPDATE    your_table
SET     Gender = 'Female'
WHERE     (Gender = 'Male')

ALTER TABLE your_table ENABLE TRIGGER [the_trigger_name]

3
固定触发器而不是禁用触发器会更好吗?创建这些触发器是有原因的,不是吗?您可以通过禁用触发器来跳过某些重要功能...
TT。

2
@TT。是的,但是请在答案中看到粗体字。如果不需要为要运行的任何查询执行触发器,则可以将查询修改为禁用然后启用触发器。
jk。

在查询期间更改表绝对是可怕的。如果您需要跳过触发器,请按每个连接执行。
Ben Voigt

25
SELECT COLUMN 
    FROM TABLE 
WHERE columns_name
    IN ( SELECT COLUMN FROM TABLE WHERE columns_name = 'value');

注意:当我们使用子查询时,我们必须关注以下几点:

  1. 如果在这种情况下我们的子查询返回1值,则需要使用(=,!=,<>,<,> ..)
  2. 其他(多个值),在这种情况下,我们需要使用(任何,全部,一些)

13
cost = Select Supplier_Item.Price from Supplier_Item,orderdetails,Supplier 
   where Supplier_Item.SKU=OrderDetails.Sku and 
      Supplier_Item.SupplierId=Supplier.SupplierID

该子查询返回多个值,SQL抱怨说,因为它不能为单个记录中的成本分配多个值。

一些想法:

  1. 修复数据,以使现有子查询仅返回1条记录
  2. 修复子查询,使其仅返回一条记录
  3. 在子查询中添加前1个并按其排序(DBA讨厌的讨厌解决方案-但它“有效”)
  4. 使用用户定义的函数将子查询的结果连接为单个字符串

5
在3; 所有有能力的开发人员也应该对此表示讨厌。前段时间有一个关于“ Pet Peeves”的问题;我的意思是:“仅仅因为没有错误消息,并不意味着它在起作用!”。也就是说,您可以添加#5:重构整个查询;即,不获取客户和“查找”发票;而不是获取发票和“查找”客户。
幻灭了

10

您的数据不正确,或者不是您认为的那样结构化。可能两者都有。

要证明/反驳此假设,请运行以下查询:

SELECT * from
(
    SELECT count(*) as c, Supplier_Item.SKU
    FROM Supplier_Item
    INNER JOIN orderdetails
        ON Supplier_Item.sku = orderdetails.sku
    INNER JOIN Supplier
        ON Supplier_item.supplierID = Supplier.SupplierID
    GROUP BY Supplier_Item.SKU
) x
WHERE c > 1
ORDER BY c DESC

如果仅返回几行,则您的数据不正确。如果它返回很多行,那么您的数据就不会按照您认为的那样结构化。(如果返回零行,那我错了。

我猜您的订单SKU多次包含相同的内容(两个单独的订单项,两者都订购相同SKU)。


10

解决方法是停止使用相关子查询,而改用联接。相关子查询本质上是游标,因为它们会导致查询逐行运行,因此应避免使用。

如果只想匹配一条记录,则可能需要在联接中使用派生表才能在字段中获取所需的值;如果需要两个值,那么普通方法join将做到这一点,但是您将获得同一id的多条记录在结果集中。如果只想要一个,则需要确定代码中的哪个,然后在代码中进行操作,可以将top 1搭配order by使用max(),可以将搭配使用,也可以将搭配使用min(),等等,这取决于您对数据的实际需求。


9

我在数据库示例中有一个相同的问题,in而不是使用:=Northwind

查询是:查找1997年下订单的公司

试试这个 :

SELECT CompanyName
    FROM Customers
WHERE CustomerID IN (
                        SELECT CustomerID 
                            FROM Orders 
                        WHERE YEAR(OrderDate) = '1997'
                    );

而不是:

SELECT CompanyName
    FROM Customers
WHERE CustomerID =
(
    SELECT CustomerID 
        FROM Orders 
    WHERE YEAR(OrderDate) = '1997'
);

6

select的费用部分中的select语句返回多个值。您需要添加更多的where子句,或使用聚合。


4

该错误表明此子查询返回的行多于1行:

(Select Supplier_Item.Price from Supplier_Item,orderdetails,Supplier where Supplier_Item.SKU=OrderDetails.Sku and Supplier_Item.SupplierId=Supplier.SupplierID )

您可能不想在子查询中包括orderdetails和provider表,因为您想引用外部查询中从这些表中选择的值。因此,我认为您希望子查询变得简单:

(Select Supplier_Item.Price from Supplier_Item where Supplier_Item.SKU=OrderDetails.Sku and Supplier_Item.SupplierId=Supplier.SupplierID )

我建议您阅读相关子查询和不相关子查询。


3

正如其他人所建议的那样,最好的方法是使用联接而不是变量分配。重新编写查询以使用联接(并使用显式联接语法代替隐式联接(这也是建议的,这是最佳做法),这是最佳做法):

select  
  OrderDetails.Sku,
  OrderDetails.mf_item_number,
  OrderDetails.Qty,
  OrderDetails.Price,
  Supplier.SupplierId, 
  Supplier.SupplierName,
  Supplier.DropShipFees, 
  Supplier_Item.Price as cost
from 
  OrderDetails
join Supplier on OrderDetails.Mfr_ID = Supplier.SupplierId
join Group_Master on Group_Master.Sku = OrderDetails.Sku 
join Supplier_Item on 
  Supplier_Item.SKU=OrderDetails.Sku and Supplier_Item.SupplierId=Supplier.SupplierID 
where 
  invoiceid='339740' 

1

即使在原始帖子发布9年后,这也对我有所帮助。

如果您毫无提示地收到这些类型的错误,则应该有一个触发器,与该表相关的函数,并且显然应该以一个SP结尾,或者以选择/过滤不使用Primary Unique列的数据作为函数。如果您使用“主要唯一身份”列进行搜索/过滤,则不会有任何多个结果。特别是在为声明的变量分配值时。SP永远不会给您en错误,而只会给您运行时错误。

 "System.Data.SqlClient.SqlException (0x80131904): Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
    The statement has been terminated."

以我为例,显然没有任何线索,只有此错误消息。有一个触发器连接到该表,并且由该触发器更新的表还具有另一个触发器,同样,它以两个触发器结束,最后以一个SP结束。SP包含一个select子句,该子句导致多行。

SET @Variable1 =(
        SELECT column_gonna_asign
        FROM dbo.your_db
        WHERE Non_primary_non_unique_key= @Variable2

如果返回多行,则麻烦。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.