【问题标题】:SQL Server Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >=SQL Server 子查询返回超过 1 个值。当子查询跟随 =、!=、<、<=、>、>= 时,这是不允许的
【发布时间】:2011-02-08 20:07:47
【问题描述】:

我运行以下查询:

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 个值。当子查询跟随 =、!=、、>= 或子查询用作表达式时,这是不允许的。

有什么想法吗?

【问题讨论】:

  • 哦,停止使用隐含的连接语法,这是一种非常糟糕的做法,更难维护,更容易出错。
  • @HLGEM 为什么它的做法很糟糕,更难维护,更容易出错?
  • 这些表连接在哪些字段上?提示:我无法判断的事实是问题所在。

标签: sql sql-server tsql


【解决方案1】:

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

【讨论】:

    【解决方案2】:
    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 和 order by(DBA 讨厌的讨厌的解决方案 - 但它“有效”)
    4. 使用用户定义的函数将子查询的结果连接成一个字符串

    【讨论】:

    • 在 3;所有有能力的开发人员也应该讨厌这样。前段时间有一个关于“皮皮鬼”的问题;而我的会是:“仅仅因为没有错误消息,并不意味着它'有效'!”。也就是说,您可以添加 #5:重组整个查询;即,而不是获取客户和“查找”发票;而是获取发票和“查找”客户。
    【解决方案3】:

    该错误表明此子查询返回的行数超过 1 行:

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

    您可能不想在子查询中包含 orderdetails 和供应商表,因为您想在外部查询中引用从这些表中选择的值。所以我认为你希望子查询很简单:

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

    我建议您阅读相关子查询与非相关子查询。

    【讨论】:

      【解决方案4】:

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

      如果您只想匹配一条记录,您可能需要在连接中使用派生表才能在字段中获取所需的值,如果您需要两个值,那么普通的join 会这样做,但您会得到结果集中相同 id 的多条记录。如果你只想要一个,你需要决定哪一个并在代码中执行,你可以使用top 1order by,你可以使用max(),你可以使用min()等,取决于您对数据的真正要求是什么。

      【讨论】:

        【解决方案5】:

        正如其他人所建议的,最好的方法是使用连接而不是变量赋值。重写您的查询以使用连接(并使用显式连接语法而不是隐式连接,这也是建议的 - 并且是最佳实践),您会得到这样的结果:

        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' 
        

        【讨论】:

          【解决方案6】:

          试试这个:

          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 列。查看返回的不同成本值并找出导致不同值的原因。然后询问某人他们想要哪个成本值,并将条件添加到将选择该成本的查询中。

          【讨论】:

            【解决方案7】:

            要么你的数据不好,要么它的结构不像你想象的那样。可能两者兼而有之。

            要证明/反驳这个假设,运行这个查询:

            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
            

            如果只返回几行,那么你的数据是错误的。如果它返回 lots 行,那么 您的数据的结构不是您认为的那样。(如果它返回零行,我错了。)

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

            【讨论】:

              【解决方案8】:

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

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

              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]
              

              【讨论】:

              • 修复触发器而不是禁用它们不是更好吗?创建这些触发器是有原因的,不是吗?您可以通过禁用触发器来绕过一些重要功能...
              • @TT。是的,但请参阅答案中的粗体文本。如果不需要为您尝试运行的任何查询执行触发器,您可以修改查询以禁用然后启用触发器。
              • 在查询期间更改表绝对是可怕的。如果您需要跳过触发器,请在每个连接的基础上进行。
              【解决方案9】:
              SELECT COLUMN 
                  FROM TABLE 
              WHERE columns_name
                  IN ( SELECT COLUMN FROM TABLE WHERE columns_name = 'value');
              

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

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

              【讨论】:

                【解决方案10】:

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

                【讨论】:

                  【解决方案11】:

                  即使在最初发布 9 年后,这对我也有帮助。

                  如果您在没有任何线索的情况下收到这些类型的错误,则应该有一个触发器、与该表相关的函数,并且显然它应该以一个 SP 结尾,或者具有选择/过滤数据的函数 NOT USING 主要唯一列。如果您使用“主要唯一性”列进行搜索/过滤,则不会有多个结果。特别是当您为声明的变量赋值时。 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
                  

                  如果这返回多行,你就有麻烦了。

                  【讨论】:

                    猜你喜欢
                    • 2014-10-21
                    • 2012-06-04
                    • 2016-08-02
                    • 2019-10-13
                    • 1970-01-01
                    相关资源
                    最近更新 更多