Die SQL Server-Unterabfrage hat mehr als einen Wert zurückgegeben. Dies ist nicht zulässig, wenn die Unterabfrage folgt = ,! =, <, <=,>,> =

81

Ich führe die folgende Abfrage aus:

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  

Ich erhalte folgende Fehlermeldung:

Nachricht 512, Ebene 16, Status 1, Zeile 2 Die Unterabfrage hat mehr als 1 Wert zurückgegeben. Dies ist nicht zulässig, wenn die Unterabfrage folgt = ,! =, <, <=,>,> = Oder wenn die Unterabfrage als Ausdruck verwendet wird.

Irgendwelche Ideen?

Anil kumar
quelle
39
Oh und hör auf, die implizite Join-Syntax zu verwenden. Es ist eine sehr schlechte Praxis, schwieriger zu pflegen und leichter Fehler zu machen.
HLGEM
1
@HLGEM warum ist es schlechte Praxis, schwerer zu pflegen und leichter Fehler zu machen?
Reggaeguitar
5
In welchen Feldern werden diese Tabellen verknüpft? Hinweis: Die Tatsache, dass ich nicht sagen kann, ist das Problem.
Naughtilus

Antworten:

48

Versuche dies:

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'

Dies gibt mehrere Zeilen zurück, die bis auf die costSpalte identisch sind . Schauen Sie sich die verschiedenen Kostenwerte an, die zurückgegeben werden, und finden Sie heraus, was die verschiedenen Werte verursacht. Fragen Sie dann jemanden, welchen Kostenwert er möchte, und fügen Sie der Abfrage die Kriterien hinzu, mit denen diese Kosten ausgewählt werden.

Jeffrey L Whitledge
quelle
42

Überprüfen Sie, ob die Tabelle, für die Sie Abfragen ausführen möchten, Trigger enthält. Sie können diesen Fehler manchmal auslösen, wenn sie versuchen, den in der Tabelle enthaltenen Trigger zum Aktualisieren / Auswählen / Einfügen auszuführen.

Sie können Ihre Abfrage so ändern, dass sie deaktiviert wird, und dann den Trigger aktivieren, wenn der Trigger NICHT für die Abfrage ausgeführt werden muss, die Sie ausführen möchten .

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.
quelle
3
Wäre es nicht besser, die Auslöser zu reparieren, als sie zu deaktivieren? Diese Auslöser wurden aus einem bestimmten Grund erstellt, nicht wahr? Sie können einige wichtige Funktionen umgehen, indem Sie die Auslöser deaktivieren ...
TT.
2
@TT. Ja, aber bitte beachten Sie den fettgedruckten Text in der Antwort. Sie können Ihre Abfrage so ändern, dass sie deaktiviert wird, und dann den Trigger aktivieren, wenn der Trigger NICHT für die Abfrage ausgeführt werden muss, die Sie ausführen möchten.
jk.
Das Ändern der Tabelle während der Abfrage ist absolut schrecklich. Wenn Sie den Trigger überspringen müssen, tun Sie dies pro Verbindung.
Ben Voigt
25
SELECT COLUMN 
    FROM TABLE 
WHERE columns_name
    IN ( SELECT COLUMN FROM TABLE WHERE columns_name = 'value');

Hinweis: Wenn wir eine Unterabfrage verwenden, müssen wir uns auf folgende Punkte konzentrieren:

  1. Wenn unsere Unterabfrage in diesem Fall 1 Wert zurückgibt, müssen wir (= ,! =, <>, <,> ....) verwenden.
  2. sonst (mehr als ein Wert) müssen wir in diesem Fall verwenden (in, jedem, allen, einigen)
Diyar Sereroy
quelle
13
cost = Select Supplier_Item.Price from Supplier_Item,orderdetails,Supplier 
   where Supplier_Item.SKU=OrderDetails.Sku and 
      Supplier_Item.SupplierId=Supplier.SupplierID

Diese Unterabfrage gibt mehrere Werte zurück. SQL beschwert sich, weil es nicht möglich ist, den Kosten in einem einzelnen Datensatz mehrere Werte zuzuweisen.

Einige Ideen:

  1. Korrigieren Sie die Daten so, dass die vorhandene Unterabfrage nur 1 Datensatz zurückgibt
  2. Korrigieren Sie die Unterabfrage so, dass nur ein Datensatz zurückgegeben wird
  3. Fügen Sie eine Top 1 hinzu und ordnen Sie nach der Unterabfrage (böse Lösung, die DBAs hassen - aber es "funktioniert")
  4. Verwenden Sie eine benutzerdefinierte Funktion, um die Ergebnisse der Unterabfrage zu einer einzelnen Zeichenfolge zu verketten
Mayo
quelle
5
Auf 3; ALLE kompetenten Entwickler sollten das auch hassen. Vor einiger Zeit gab es eine Frage zu 'Pet Peeves'. und meins wäre: "Nur weil es keine Fehlermeldungen gibt, heißt das nicht, dass es 'funktioniert'!". Das heißt, Sie können # 5 hinzufügen: Restrukturieren Sie die gesamte Abfrage; dh anstatt Kunden- und 'Nachschlag'-Rechnungen zu erhalten; Holen Sie sich lieber Rechnungen und suchen Sie Kunden.
Desillusioniert
10

Entweder sind Ihre Daten schlecht oder sie sind nicht so strukturiert, wie Sie denken. Möglicherweise beides.

Führen Sie diese Abfrage aus, um diese Hypothese zu beweisen / zu widerlegen:

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

Wenn dies nur wenige Zeilen zurückgibt, sind Ihre Daten fehlerhaft . Wenn viele Zeilen zurückgegeben werden, sind Ihre Daten nicht so strukturiert, wie Sie denken. (Wenn es null Zeilen zurückgibt, irre ich mich. )

Ich vermute, dass Sie Bestellungen haben, die dasselbe SKUmehrmals enthalten (zwei separate Werbebuchungen, beide bestellen dasselbe SKU).

Egrunin
quelle
10

Die Lösung besteht darin, keine korrelierten Unterabfragen mehr zu verwenden und stattdessen Verknüpfungen zu verwenden. Korrelierte Unterabfragen sind im Wesentlichen Cursor, da sie dazu führen, dass die Abfrage zeilenweise ausgeführt wird und vermieden werden sollte.

Möglicherweise benötigen Sie eine abgeleitete Tabelle im Join, um den gewünschten Wert im Feld zu erhalten, wenn nur ein Datensatz übereinstimmen soll. Wenn Sie beide Werte benötigen, joinwird dies vom normalen Benutzer ausgeführt, Sie erhalten jedoch mehrere Datensätze für dieselbe ID in der Ergebnismenge. Wenn Sie nur eine möchten, müssen Sie entscheiden, welche und dies im Code tun. Sie können eine top 1mit einer verwenden order by, Sie können verwenden max(), Sie können verwenden min()usw., je nachdem, was Ihre tatsächlichen Anforderungen an die Daten sind.

HLGEM
quelle
9

Ich hatte das gleiche Problem, habe ich instatt =, aus der NorthwindDatenbank Beispiel:

Die Abfrage lautet: Finden Sie die Unternehmen, die 1997 Bestellungen aufgegeben haben

Versuche dies :

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

Stattdessen :

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

Die select-Anweisung im Kostenteil Ihrer Auswahl gibt mehr als einen Wert zurück. Sie müssen weitere where-Klauseln hinzufügen oder eine Aggregation verwenden.

cjk
quelle
4

Der Fehler impliziert, dass diese Unterabfrage mehr als eine Zeile zurückgibt:

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

Sie möchten die Bestelldetails und Lieferantentabellen wahrscheinlich nicht in die Unterabfrage aufnehmen, da Sie in der äußeren Abfrage auf die aus diesen Tabellen ausgewählten Werte verweisen möchten. Ich denke, Sie möchten, dass die Unterabfrage einfach lautet:

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

Ich schlage vor, Sie informieren sich über korrelierte und nicht korrelierte Unterabfragen.

Dave Costa
quelle
3

Wie andere vorgeschlagen haben, ist der beste Weg, dies zu tun, die Verwendung eines Joins anstelle der Variablenzuweisung. Wenn Sie Ihre Abfrage neu schreiben, um einen Join zu verwenden (und die explizite Join-Syntax anstelle des impliziten Joins verwenden, der ebenfalls vorgeschlagen wurde - und die beste Vorgehensweise ist), erhalten Sie Folgendes:

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
quelle
1

Auch nach 9 Jahren des ursprünglichen Beitrags hat mir das geholfen.

Wenn Sie diese Art von Fehlern ohne Anhaltspunkt erhalten, sollte es einen Auslöser, eine Funktion in Bezug auf die Tabelle und offensichtlich einen SP oder eine Funktion zum Auswählen / Filtern von Daten geben, die KEINE primäre eindeutige Spalte verwenden. Wenn Sie mithilfe der Spalte "Primär eindeutig" suchen / filtern, werden nicht mehrere Ergebnisse angezeigt. Insbesondere, wenn Sie einer deklarierten Variablen einen Wert zuweisen. Der SP gibt Ihnen nie einen Fehler, sondern nur einen Laufzeitfehler.

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

In meinem Fall gab es offensichtlich keinen Hinweis, sondern nur diese Fehlermeldung. Es war ein Trigger mit der Tabelle verbunden, und die durch den Trigger aktualisierte Tabelle hatte auch einen anderen Trigger. Ebenso endete sie mit zwei Triggern und am Ende mit einem SP. Der SP hatte eine select-Klausel, die zu mehreren Zeilen führte.

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

Wenn dies mehrere Zeilen zurückgibt, sind Sie in Schwierigkeiten.

Shammie
quelle