Truy vấn con SQL Server trả về nhiều hơn 1 giá trị. Điều này không được phép khi truy vấn con theo sau =,! =, <, <=,>,> =


81

Tôi chạy truy vấn sau:

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  

Tôi nhận được lỗi sau đây:

Msg 512, Cấp 16, Trạng thái 1, Dòng 2 Truy vấn con trả về nhiều hơn 1 giá trị. Điều này không được phép khi truy vấn con theo sau =,! =, <, <=,>,> = Hoặc khi truy vấn con được sử dụng như một biểu thức.

Có ý kiến ​​gì không?


39
Ồ và ngừng sử dụng cú pháp nối ngụ ý, Đây là một thực hành rất kém, khó bảo trì hơn và dễ mắc lỗi hơn.
HLGEM

1
@HLGEM tại sao nó thực hành kém, khó bảo trì hơn và dễ mắc lỗi hơn?
reggaeguitar

5
Các bảng này được nối trên những trường nào? Gợi ý: thực tế mà tôi không thể biết được chính là vấn đề.
naughtilus

Câu trả lời:


48

Thử đi:

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'

Điều này sẽ trả về nhiều hàng giống hệt nhau ngoại trừ costcột. Xem xét các giá trị chi phí khác nhau được trả lại và tìm ra nguyên nhân gây ra các giá trị khác nhau. Sau đó hỏi ai đó họ muốn giá trị chi phí nào và thêm tiêu chí vào truy vấn sẽ chọn chi phí đó.


42

Kiểm tra xem có bất kỳ trình kích hoạt nào trên bảng mà bạn đang cố thực hiện các truy vấn hay không. Đôi khi họ có thể gặp lỗi này khi họ đang cố gắng chạy trình kích hoạt cập nhật / chọn / chèn trên bảng.

Bạn có thể sửa đổi truy vấn của mình để vô hiệu hóa sau đó bật trình kích hoạt nếu trình kích hoạt KHÔNG cần được thực thi cho bất kỳ truy vấn nào bạn đang cố gắng chạy.

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]

3
Sẽ tốt hơn nếu sửa (các) trình kích hoạt hơn là vô hiệu hóa chúng? Những kích hoạt đó được tạo ra vì một lý do, không? Bạn có thể bỏ qua một số chức năng quan trọng bằng cách tắt (các) trình kích hoạt ...
TT.

2
@TT. Có, nhưng vui lòng xem văn bản in đậm trong câu trả lời. Bạn có thể sửa đổi truy vấn của mình để vô hiệu hóa sau đó bật trình kích hoạt nếu trình kích hoạt KHÔNG cần thực hiện cho bất kỳ truy vấn nào bạn đang cố gắng chạy.
jk.

Thay đổi bảng trong quá trình truy vấn là hoàn toàn khủng khiếp. Nếu bạn cần bỏ qua trình kích hoạt, hãy thực hiện trên cơ sở từng kết nối.
Ben Voigt

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

lưu ý: khi chúng ta đang sử dụng truy vấn phụ, chúng ta phải tập trung vào những điểm sau:

  1. nếu truy vấn phụ của chúng tôi trả về 1 giá trị trong trường hợp này, chúng tôi cần sử dụng (=,! =, <>, <,> ....)
  2. else (nhiều hơn một giá trị), trong trường hợp này chúng ta cần sử dụng (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

Truy vấn con này trả về nhiều giá trị, SQL đang phàn nàn vì nó không thể gán nhiều giá trị thành giá trong một bản ghi.

Một vài ý tưởng:

  1. Sửa dữ liệu sao cho truy vấn con hiện tại chỉ trả về 1 bản ghi
  2. Sửa truy vấn con để nó chỉ trả về một bản ghi
  3. Thêm top 1 và đặt hàng theo truy vấn con (giải pháp khó chịu mà DBA rất ghét - nhưng nó "hoạt động")
  4. Sử dụng một hàm do người dùng xác định để nối kết quả của truy vấn con thành một chuỗi đơn

5
Trên 3; TẤT CẢ các nhà phát triển có năng lực cũng nên ghét điều đó. Có một câu hỏi trên 'Pet Peeves' một thời gian trước; và của tôi sẽ là: "Chỉ vì không có thông báo lỗi, không có nghĩa là nó 'hoạt động'!". Điều đó nói rằng, bạn có thể thêm # 5: Cơ cấu lại toàn bộ truy vấn; tức là thay vì lấy hóa đơn của khách hàng và 'tra cứu'; thay vì lấy hóa đơn và 'tra cứu' khách hàng.
Vỡ mộng vào

10

Dữ liệu của bạn không tốt hoặc không được cấu trúc theo cách bạn nghĩ. Có thể là cả hai.

Để chứng minh / bác bỏ giả thuyết này, hãy chạy truy vấn sau:

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

Nếu điều này chỉ trả về một vài hàng, thì dữ liệu của bạn không tốt . Nếu nó trả về nhiều hàng, thì dữ liệu của bạn không được cấu trúc theo cách bạn nghĩ. (Nếu nó trả về 0 hàng, tôi đã nhầm. )

Tôi đoán rằng bạn có các đơn đặt hàng chứa SKUnhiều lần giống nhau (hai mục hàng riêng biệt, cả hai đều đặt hàng giống nhau SKU).


10

Cách khắc phục là ngừng sử dụng các truy vấn con tương quan và thay vào đó sử dụng các phép nối. Các truy vấn con có liên quan về cơ bản là con trỏ vì chúng khiến truy vấn chạy theo từng hàng và nên tránh.

Bạn có thể cần một bảng dẫn xuất trong phép nối để nhận giá trị bạn muốn trong trường nếu bạn chỉ muốn một bản ghi khớp với nhau, nếu bạn cần cả hai giá trị thì thông thường joinsẽ làm điều đó nhưng bạn sẽ nhận được nhiều bản ghi cho cùng một id trong tập kết quả. Nếu bạn chỉ muốn một, bạn cần phải quyết định cái nào và thực hiện điều đó trong mã, bạn có thể sử dụng a top 1với một order by, bạn có thể sử dụng max(), bạn có thể sử dụng min(), v.v., tùy thuộc vào yêu cầu thực sự của bạn đối với dữ liệu là gì.


9

Tôi đã gặp vấn đề tương tự, tôi đã sử dụng inthay thế =, từ Northwindví dụ cơ sở dữ liệu:

Truy vấn là: Tìm các công ty đã đặt hàng vào năm 1997

Thử đi :

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

Thay vì đó :

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

6

Câu lệnh select trong phần chi phí của lựa chọn của bạn đang trả về nhiều hơn một giá trị. Bạn cần thêm nhiều mệnh đề where hoặc sử dụng tổng hợp.


4

Lỗi ngụ ý rằng truy vấn con này đang trả về nhiều hơn 1 hàng:

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

Bạn có thể không muốn bao gồm chi tiết đơn hàng và bảng nhà cung cấp trong truy vấn con, vì bạn muốn tham chiếu các giá trị được chọn từ các bảng đó trong truy vấn bên ngoài. Vì vậy, tôi nghĩ bạn muốn truy vấn con chỉ đơn giản là:

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

Tôi khuyên bạn nên đọc các truy vấn phụ tương quan và không tương quan.


3

Như những người khác đã đề xuất, cách tốt nhất để làm điều này là sử dụng phép nối thay vì phép gán biến. Viết lại truy vấn của bạn để sử dụng một phép nối (và sử dụng cú pháp nối rõ ràng thay vì phép nối ngầm, cũng được đề xuất - và là phương pháp hay nhất), bạn sẽ nhận được một cái gì đó như sau:

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' 

1

Ngay cả sau 9 năm của bài đăng ban đầu, điều này đã giúp tôi.

Nếu bạn nhận được các loại lỗi này mà không có bất kỳ manh mối nào, thì phải có một trình kích hoạt, chức năng liên quan đến bảng và rõ ràng là nó phải kết thúc bằng một SP hoặc chức năng chọn / lọc dữ liệu KHÔNG SỬ DỤNG cột Chính Duy nhất. Nếu bạn đang tìm kiếm / lọc bằng cột Số duy nhất Chính thì sẽ không có bất kỳ kết quả nào. Đặc biệt là khi bạn đang gán giá trị cho một biến đã khai báo. SP không bao giờ cho bạn lỗi vi mà chỉ là lỗi thời gian chạy.

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

Trong trường hợp của tôi rõ ràng là không có manh mối, nhưng chỉ có thông báo lỗi này. Có một trình kích hoạt được kết nối với bảng và bảng được trình kích hoạt cập nhật cũng có một trình kích hoạt khác, tương tự như vậy, nó kết thúc với hai trình kích hoạt và cuối cùng là một SP. SP có một mệnh đề chọn dẫn đến nhiều hàng.

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

Nếu điều này trả về nhiều hàng, bạn đang gặp rắc rối.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.