web-dev-qa-db-fra.com

La sous-requête SQL Server a renvoyé plus d'une valeur. Ceci n'est pas autorisé lorsque la sous-requête suit =,! =, <, <=,>,> =

Je lance la requête suivante:

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  

Je reçois l'erreur suivante:

Msg 512, Niveau 16, Etat 1, Ligne 2 La sous-requête a renvoyé plus de 1 valeur. Ceci n'est pas autorisé lorsque la sous-requête suit =,! =, <, <=,>,> = Ou lorsque la sous-requête est utilisée comme expression.

Des idées?

70
Anilkumar

Essaye ça:

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'

Cela renverra plusieurs lignes identiques, à l'exception de la colonne cost. Examinez les différentes valeurs de coût renvoyées et déterminez la cause de ces différentes valeurs. Puis demandez à quelqu'un quelle valeur de coût ils veulent, et ajoutez les critères à la requête qui sélectionnera ce coût.

42

Vérifiez si la table sur laquelle vous essayez d'exécuter des requêtes contient des déclencheurs. Ils peuvent parfois émettre cette erreur alors qu’ils tentent d’exécuter le déclencheur update/select/insert qui se trouve sur la table.

Vous pouvez modifier votre requête pour la désactiver, puis l'activer si le déclencheur NE FAIT PAS doit être exécuté pour la requête que vous essayez d'exécuter.

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]
38
jk.
SELECT COLUMN 
    FROM TABLE 
WHERE columns_name
    IN ( SELECT COLUMN FROM TABLE WHERE columns_name = 'value');

remarque: lorsque nous utilisons une sous-requête, nous devons nous concentrer sur le point

  1. si notre sous requête retourne une valeur dans ce cas, nous utilisons (=,! =, <>, <,> ....)
  2. else (plus d'une valeur) dans ce cas, nous utilisons (dans, n'importe lequel, tous, certains)
19
Diyar sereroy
cost = Select Supplier_Item.Price from Supplier_Item,orderdetails,Supplier 
   where Supplier_Item.SKU=OrderDetails.Sku and 
      Supplier_Item.SupplierId=Supplier.SupplierID

Cette sous-requête renvoie plusieurs valeurs. SQL se plaint car il ne peut pas affecter plusieurs valeurs au coût dans un seul enregistrement.

Quelques idées:

  1. Corrigez les données de sorte que la sous-requête existante ne renvoie qu'un seul enregistrement.
  2. Corrige la sous-requête de telle sorte qu'elle ne retourne qu'un seul enregistrement
  3. Ajouter un top 1 et ordre par à la sous-requête (solution désagréable que les administrateurs de bases de données détestent - mais cela "fonctionne")
  4. Utiliser une fonction définie par l'utilisateur pour concaténer les résultats de la sous-requête en une seule chaîne
13
Mayo

Le correctif consiste à arrêter d'utiliser des sous-requêtes corrélées et à utiliser des jointures à la place. Les sous-requêtes corrélées sont essentiellement des curseurs car elles entraînent l'exécution de la requête ligne par ligne et doivent donc être évitées.

Vous aurez peut-être besoin d'une table dérivée dans la jointure pour obtenir la valeur souhaitée dans le champ si vous souhaitez qu'un seul enregistrement corresponde. Si vous avez besoin des deux valeurs, l'ordinaire join le fera, mais vous obtiendrez plusieurs enregistrements pour le même identifiant dans le jeu de résultats. Si vous n'en voulez qu'un, vous devez choisir lequel et le faire dans le code, vous pouvez utiliser un top 1 avec un order by, vous pouvez utiliser max(), vous pouvez utiliser min(), etc., en fonction de vos besoins réels pour les données.

10
HLGEM

Soit vos données sont mauvaises, soit elles ne sont pas structurées comme vous le pensez. Peut-être les deux.

Pour prouver/réfuter cette hypothèse, exécutez cette requête:

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 cela ne renvoie que quelques lignes, alors vos données sont incorrectes . S'il renvoie beaucoup de lignes, alors vos données ne sont pas structurées comme vous le pensez. (si elles ne renvoient aucune ligne , je me trompe. )

J'imagine que vous avez des ordres contenant plusieurs fois le même SKU (deux postes distincts, tous deux ordonnant le même SKU).

9
egrunin

J'ai eu le même problème, j'ai utilisé in au lieu de =, à partir de l'exemple de base de données Northwind:

La requête est: trouver les sociétés qui ont passé des commandes en 1997

Essaye ça :

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

Au lieu de :

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

L'instruction select dans la partie des coûts de votre sélection renvoie plusieurs valeurs. Vous devez ajouter d'autres clauses Where ou utiliser une agrégation.

6
cjk

L'erreur implique que cette sous-requête renvoie plus d'une ligne:

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

Vous ne souhaitez probablement pas inclure les tables de détails de commande et de fournisseur dans la sous-requête, car vous souhaitez référencer les valeurs sélectionnées à partir de ces tables dans la requête externe. Je pense donc que vous voulez que la sous-requête soit simplement:

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

Je vous suggère de lire sur les sous-requêtes corrélées par rapport aux sous-requêtes non corrélées.

4
Dave Costa

Comme d'autres l'ont suggéré, la meilleure façon de procéder consiste à utiliser une jointure au lieu d'une affectation de variable. Réécrivez votre requête pour utiliser une jointure (et en utilisant la syntaxe de jointure explicite au lieu de la jointure implicite, ce qui a également été suggéré - et constitue la meilleure pratique), vous obtiendrez quelque chose comme ceci:

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' 
3
KP Taylor