La subconsulta de SQL Server devolvió más de 1 valor. Esto no está permitido cuando la subconsulta sigue =,! =, <, <=,>,> =

81

Ejecuto la siguiente consulta:

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  

Obtuve el siguiente error:

Msg 512, nivel 16, estado 1, línea 2 La subconsulta devolvió más de 1 valor. Esto no está permitido cuando la subconsulta sigue a =,! =, <, <=,>,> = O cuando la subconsulta se utiliza como expresión.

¿Algunas ideas?

Anil Kumar
fuente
39
Ah, y deje de usar la sintaxis de unión implícita. Es una práctica muy pobre, más difícil de mantener y más fácil de cometer errores.
HLGEM
1
@HLGEM ¿por qué es una práctica deficiente, más difícil de mantener y más fácil de cometer errores?
reggaeguitar
5
¿En qué campos se unen estas tablas? Pista: el problema es el hecho de que no puedo decirlo.
naughtilus

Respuestas:

48

Prueba esto:

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'

Esto devolverá varias filas que son idénticas excepto por la costcolumna. Observe los diferentes valores de costo que se devuelven y averigüe qué está causando los diferentes valores. Luego, pregúntele a alguien qué valor de costo desea y agregue los criterios a la consulta que seleccionará ese costo.

Jeffrey L. Whitledge
fuente
42

Verifique si hay algún desencadenante en la tabla contra el que está tratando de ejecutar consultas. A veces pueden arrojar este error cuando intentan ejecutar el activador de actualización / selección / inserción que está en la mesa.

Puede modificar su consulta para deshabilitar y luego habilitar el disparador si el disparador NO necesita ser ejecutado para cualquier consulta que esté intentando ejecutar.

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]
jk.
fuente
3
¿No sería mejor arreglar los disparadores en lugar de desactivarlos? Esos desencadenantes se crearon por una razón, ¿no? Puede omitir algunas funciones importantes deshabilitando el (los) disparador (es) ...
TT.
2
@TT. Sí, pero consulte el texto en negrita en la respuesta. Puede modificar su consulta para deshabilitar y luego habilitar el disparador si el disparador NO necesita ser ejecutado para cualquier consulta que esté intentando ejecutar.
jk.
Alterar la tabla durante la consulta es absolutamente terrible. Si necesita omitir el disparador, hágalo por conexión.
Ben Voigt
25
SELECT COLUMN 
    FROM TABLE 
WHERE columns_name
    IN ( SELECT COLUMN FROM TABLE WHERE columns_name = 'value');

nota: cuando usamos subconsultas debemos enfocarnos en estos puntos:

  1. si nuestra subconsulta devuelve 1 valor en este caso, necesitamos usar (=,! =, <>, <,> ....)
  2. else (más de un valor), en este caso necesitamos usar (in, any, all, some)
Diyar sereroy
fuente
13
cost = Select Supplier_Item.Price from Supplier_Item,orderdetails,Supplier 
   where Supplier_Item.SKU=OrderDetails.Sku and 
      Supplier_Item.SupplierId=Supplier.SupplierID

Esta subconsulta devuelve múltiples valores, SQL se queja porque no puede asignar múltiples valores al costo en un solo registro.

Algunas ideas:

  1. Corrija los datos de manera que la subconsulta existente devuelva solo 1 registro
  2. Corrija la subconsulta de modo que solo devuelva un registro
  3. Agregue un top 1 y ordene a la subconsulta (solución desagradable que los DBA odian, pero "funciona")
  4. Utilice una función definida por el usuario para concatenar los resultados de la subconsulta en una sola cadena
Mayonesa
fuente
5
El 3; TODOS los desarrolladores competentes también deberían odiar eso. Hubo una pregunta sobre 'Pet Peeves' hace un tiempo; y el mío sería: "¡El hecho de que no haya un mensaje de error no significa que 'funcione'!". Dicho esto, puede agregar el n. ° 5: reestructurar toda la consulta; es decir, en lugar de recibir facturas de clientes y "buscar"; en lugar de eso, obtenga facturas y "busque" clientes.
Desilusionado
10

O tus datos son incorrectos o no están estructurados de la forma que crees. Posiblemente ambos.

Para probar / refutar esta hipótesis, ejecute esta consulta:

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

Si esto devuelve solo unas pocas filas, entonces sus datos son incorrectos . Si devuelve muchas filas, significa que sus datos no están estructurados de la forma que cree. (Si devuelve cero filas, estoy equivocado ) .

Supongo que tiene pedidos que contienen lo mismo SKUvarias veces (dos líneas de pedido separadas, ambas con el mismo pedido SKU).

egrunin
fuente
10

La solución es dejar de usar subconsultas correlacionadas y usar combinaciones en su lugar. Las subconsultas correlacionadas son esencialmente cursores, ya que hacen que la consulta se ejecute fila por fila y deben evitarse.

Es posible que necesite una tabla derivada en la combinación para obtener el valor que desea en el campo si solo desea que coincida un registro, si necesita ambos valores, el ordinario joinlo hará, pero obtendrá varios registros para la misma identificación en el conjunto de resultados. Si solo desea uno, debe decidir cuál y hacerlo en el código, podría usar un top 1con un order by, podría usar max(), podría usar min(), etc., dependiendo de cuál sea su requisito real para los datos.

HLGEM
fuente
9

Tuve el mismo problema, usé en inlugar de =, del Northwindejemplo de la base de datos:

La consulta es: Encuentre las empresas que realizaron pedidos en 1997

Prueba esto :

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

En lugar de eso :

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

La declaración de selección en la parte del costo de su selección devuelve más de un valor. Debe agregar más cláusulas where o usar una agregación.

cjk
fuente
4

El error implica que esta subconsulta está devolviendo más de 1 fila:

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

Probablemente no desee incluir los detalles del pedido y las tablas de proveedores en la subconsulta, porque desea hacer referencia a los valores seleccionados de esas tablas en la consulta externa. Entonces creo que quieres que la subconsulta sea simplemente:

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

Le sugiero que lea sobre las subconsultas correlacionadas frente a las no correlacionadas.

Dave Costa
fuente
3

Como han sugerido otros, la mejor manera de hacer esto es usar una combinación en lugar de una asignación de variable. Reescribiendo su consulta para usar una combinación (y usando la sintaxis de combinación explícita en lugar de la combinación implícita, que también se sugirió, y es la mejor práctica), obtendría algo como esto:

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' 
KP Taylor
fuente
1

Incluso después de 9 años de la publicación original, esto me ayudó.

Si recibe este tipo de errores sin ninguna pista, debería haber un disparador, una función relacionada con la tabla y, obviamente, debería terminar con un SP, o una función con la selección / filtrado de datos NO UTILIZANDO la columna Principal Única. Si está buscando / filtrando utilizando la columna Principal único, no habrá múltiples resultados. Especialmente cuando asigna valor a una variable declarada. El SP nunca le da un error, solo un error de tiempo de ejecución.

 "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."

En mi caso, obviamente, no había ninguna pista, solo este mensaje de error. Había un disparador conectado a la mesa y la actualización de la tabla por el disparador también tenía otro disparador, así mismo terminó con dos disparadores y al final con un SP. El SP tenía una cláusula de selección que daba como resultado varias filas.

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

Si esto devuelve varias filas, está en problemas.

Shammie
fuente