SQL Server子查询返回了多个值。当子查询跟随=,!=,<,<=,>,>=时,这是不允许的。

101

我运行了以下查询:

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  

我得到了以下错误:

Msg 512, Level 16, State 1, Line 2 子查询返回多个值。 当子查询跟随=,!=,<,< =,>,> =时不允许这种情况,或者当子查询用作表达式时。

有什么想法?


45
请停止使用隐式联接语法,这是一种非常不好的做法,更难以维护,而且容易出错。 - HLGEM
6
为什么这是不良实践,更难以维护且更容易出错? - reggaeguitar
9
这些表格基于哪些字段连接?提示:我无法确定这一点是问题所在。 - naughtilus
2
@reggaeguitar - 就我个人而言,我发现隐式连接更难理解。实际上,我必须停下来关注WHERE子句,以确保连接被正确实现。如果隐含条件分散在子句中,那么它会变得更加困难并且降低可读性。与所有编程语言一样,语义使用是使您的SQL更易读的关键 - 所有连接都应正确定义为FROM子句的子部分 - 这样,您就知道数据来自哪里,更重要的是,为什么 - user1945782
13个回答

62

试试这个:

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 列之外都是相同的。查看返回的不同成本值,弄清楚导致不同值的原因。然后询问某人他们想要哪个成本值,并向查询添加条件以选择该成本。

56

检查一下您尝试执行查询的表上是否有任何触发器。它们有时会抛出此错误,因为它们正在尝试运行该表上的更新/选择/插入触发器。

如果不需要执行触发器以运行您尝试运行的任何查询,则可以修改查询以禁用再启用触发器。

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]

6
禁用触发器不如修复它们更好,毕竟这些触发器都是有原因被创建的。禁用触发器可能会绕过一些重要的功能... - TT.
4
@TT。是的,但请查看答案中加粗的文本。如果您正在尝试运行的任何查询不需要执行触发器,则可以修改查询以禁用然后启用触发器。 - jk.
1
在查询期间更改表格绝对是可怕的。如果你需要跳过触发器,请在每个连接基础上执行。 - Ben Voigt

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

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

  1. 如果我们的子查询返回一个值,在这种情况下,我们需要使用 (=,!=,<>,<,>....) 中的一种。
  2. 否则(返回多个值),在这种情况下,我们需要使用 (in, any, all, some ) 中的一种。

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

这个子查询返回多个值,SQL会抱怨因为它无法将多个值分配给单个记录的cost。

一些想法:

  1. 修复数据,使得现有子查询只返回1个记录
  2. 修复子查询,使其仅返回一个记录
  3. 在子查询中添加top 1和order by(DBA讨厌的可怕解决方案,但它“有效”)
  4. 使用用户定义函数将子查询结果连接成单个字符串

5
在3上;所有有能力的开发者也应该讨厌这个。之前有一个关于“Pet Peeves”的问题; 我的是:“仅仅因为没有错误信息,不意味着它是‘有效的’!”。也就是说,你可以添加#5:重新构建整个查询;例如,不是获取客户并“查找”发票,而是获取发票并“查找”客户。 - Disillusioned

12

修复方法是停止使用相关子查询,改用连接(join)代替。相关子查询本质上是游标,因为它们会导致查询逐行运行,应该避免使用。

如果您只想匹配一个记录并获取其中的值,则可能需要在连接中使用派生表来实现该目的;如果您需要两个值,则普通的join将完成此操作,但您将在结果集中获得相同ID的多个记录。如果您只想获取一条记录,则需要在代码中决定哪个值,并进行相应操作,例如可以使用带有order bytop 1max()min()等,具体取决于数据的实际要求。


12

我遇到相同的问题,我使用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'
);

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)。

6

在你的选择成本部分中,select语句返回了多个值。您需要添加更多的where子句或使用聚合。


4
该错误意味着此子查询返回了多个行:
(Select Supplier_Item.Price from Supplier_Item,orderdetails,Supplier where Supplier_Item.SKU=OrderDetails.Sku and Supplier_Item.SupplierId=Supplier.SupplierID )

您可能不想在子查询中包含orderdetails和supplier表,因为您想在外部查询中引用从这些表中选择的值。因此,我认为您只需要子查询如下所示:
(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' 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接