Link to home
Start Free TrialLog in
Avatar of Calvin Day
Calvin DayFlag for United States of America

asked on

Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

This script returns the subject error. Done this sort of thing before, been a while. Snow Blind

/*
Error Message
(16 row(s) affected)
Msg 512, Level 16, State 1, Line 59
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.

(16 row(s) affected)
*/

 declare @Po as int
  set @Po = 99308

  declare @PoHistory table
      (
       [ID] [int] identity (1, 1)
      ,[Po] [int] null
      ,[Item#] [float] null
      ,[Qty] [float] null default (0.0)
      ,[RecQty] [float] null default (0.0)
      ,[Amount] [decimal] (10, 2) default (0)
      ,[AuthorizedAmount] [decimal] (10, 2) default (0)
      ,[PendingAmount] [decimal] (10, 2) default (0)
      ,[PaidAmount] [decimal] (10, 2) default (0)
      )
            
      insert into @PoHistory
            (
             [Po]
            ,[Item#]
            ,[Qty]
            ,[RecQty]
            ,[Amount]
            ,[AuthorizedAmount]
            
            )
            (
            select
                   [PO_ID]
                  ,[ITEM_]
                  ,[QTY]
                  ,[RECVDQTY]
                  ,[TOTCOST]
                  ,[AuthorizedAmount]
            from [TVENDPOD]
            where [RECORD_] is not null
            and [PO_ID] = @Po
            )
            
      update @PoHistory set [PendingAmount] =
            (
            select
                  sum( [TOTCOST])
            from [ACCOUNTSPAYABLE_DETAIL]
            where [RECORD_] is not null
            and [PO_ID] = @Po
            and [CHECKNUMBER] = 0
            and [PAID_DATE] is null
            group by [PO_ID], [ITEM_]
            )                  
      from @PoHistory, [ACCOUNTSPAYABLE_DETAIL]
      where [ACCOUNTSPAYABLE_DETAIL].[PO_ID] = [Po]
      and [ACCOUNTSPAYABLE_DETAIL].[ITEM_] = [Item#]
                   
      select
            *
      from @PoHistory
Avatar of Pawan Kumar
Pawan Kumar
Flag of India image

Please change update statement to below and try again.

update P
SET P.[PendingAmount] = x.TOTCOST
from @PoHistory P 
CROSS APPLY 
(
	SELECT sum([TOTCOST]) [TOTCOST]
	FROM [ACCOUNTSPAYABLE_DETAIL] H 
	WHERE H.[PO_ID] = P.[Po] and H.[ITEM_] = P.[Item]
	and [PO_ID] = @Po and [CHECKNUMBER] = 0 and [PAID_DATE] is null
)x

Open in new window

Avatar of Calvin Day

ASKER

Thank you Pawan Kumar, reply ASAP midnight CST here, time for a little rest. G
Complete and formatted code for you -

DECLARE @Po AS INT
SET @Po = 99308

DECLARE @PoHistory TABLE 
(
  [ID] [int] IDENTITY (1, 1),
  [Po] [int] NULL,
  [Item] [float] NULL,
  [Qty] [float] NULL DEFAULT (0.0),
  [RecQty] [float] NULL DEFAULT (0.0),
  [Amount] [decimal](10, 2) DEFAULT (0),
  [AuthorizedAmount] [decimal](10, 2) DEFAULT (0),
  [PendingAmount] [decimal](10, 2) DEFAULT (0),
  [PaidAmount] [decimal](10, 2) DEFAULT (0)
)

INSERT INTO @PoHistory ([Po],[Item],[Qty],[RecQty],[Amount],[AuthorizedAmount])  
SELECT [PO_ID],[ITEM_],[QTY],[RECVDQTY],[TOTCOST],[AuthorizedAmount] 
FROM [TVENDPOD]
	WHERE [RECORD_] IS NOT NULL AND [PO_ID] = @Po

UPDATE P
SET P.[PendingAmount] = x.TOTCOST
FROM @PoHistory P
CROSS APPLY 
(
	SELECT
	  SUM([TOTCOST]) [TOTCOST]
	FROM [ACCOUNTSPAYABLE_DETAIL] H
	WHERE H.[PO_ID] = P.[Po] AND H.[ITEM_] = P.[Item]
	AND [PO_ID] = @Po AND [CHECKNUMBER] = 0 AND [PAID_DATE] IS NULL
) x

Open in new window

Inner join can also be used ...another way..
BUT CROSS APPLY will always be helpful and fast in these kind of cases.

UDECLARE @Po AS INT
SET @Po = 99308

DECLARE @PoHistory TABLE 
(
  [ID] [int] IDENTITY (1, 1),
  [Po] [int] NULL,
  [Item] [float] NULL,
  [Qty] [float] NULL DEFAULT (0.0),
  [RecQty] [float] NULL DEFAULT (0.0),
  [Amount] [decimal](10, 2) DEFAULT (0),
  [AuthorizedAmount] [decimal](10, 2) DEFAULT (0),
  [PendingAmount] [decimal](10, 2) DEFAULT (0),
  [PaidAmount] [decimal](10, 2) DEFAULT (0)
)

INSERT INTO @PoHistory ([Po],[Item],[Qty],[RecQty],[Amount],[AuthorizedAmount])  
SELECT [PO_ID],[ITEM_],[QTY],[RECVDQTY],[TOTCOST],[AuthorizedAmount] 
FROM [TVENDPOD]
	WHERE [RECORD_] IS NOT NULL AND [PO_ID] = @Po

UPDATE P
SET P.[PendingAmount] = x.TOTCOST
FROM @PoHistory P
INNER JOIN 
(
	SELECT
	  SUM([TOTCOST]) [TOTCOST] , H.[PO_ID],H.[ITEM_]
	FROM [ACCOUNTSPAYABLE_DETAIL] H
	WHERE [PO_ID] = @Po AND [CHECKNUMBER] = 0 AND [PAID_DATE] IS NULL
	GROUP BY H.[PO_ID],H.[ITEM_]
)x ON x.[PO_ID] = p.[Po] AND x.[ITEM_] = P.[Item]

select  * from @PoHistory

Open in new window

Avatar of Ryan Chong
Msg 512, Level 16, State 1, Line 59

your codes look ok...which line is line 59?
@Ryan -
The update statement is incorrect. The inner query is returning multiple records and we are assigning that to single. So effectively the author is updating single record with his statement but Multiple records needs to be updated.

@Greg -
Have you tried my suggestions? Thank you.
The inner query is returning multiple records and we are assigning that to single.

it's returns a Sum, so it shouldn't return multiple records

select
                  sum( [TOTCOST])
            from [ACCOUNTSPAYABLE_DETAIL]
            where [RECORD_] is not null
            and [PO_ID] = @Po
            and [CHECKNUMBER] = 0
            and [PAID_DATE] is null
            group by [PO_ID], [ITEM_]
wait, you probably right. I didn't see the group by:

select                   sum( [TOTCOST])
            from [ACCOUNTSPAYABLE_DETAIL]
            where [RECORD_] is not null
            and [PO_ID] = @Po
            and [CHECKNUMBER] = 0
            and [PAID_DATE] is null
            group by [PO_ID], [ITEM_]
@Ryan -
SAMPLE FOR YOU --- MULTIPLE RECORDS

CREATE TABLE testSUM
(
	  [PO_ID] INT 
	, [ITEM_] INT 
	, [TOTCOST] INT 
)
GO

INSERT INTO testSUM VALUES ( 1,1,100 ) , ( 1,2,30 ) , ( 1,1,300 ) , (3,4,20)
GO

SELECT SUM([TOTCOST]) [TOTCOST] 
FROM testSUM
group by [PO_ID], [ITEM_]

/*------------------------
MULTIPLE RECORDS
------------------------*/
TOTCOST
-----------
400
30
20

(3 row(s) affected)

Open in new window

try this to handle inner query error:

update @PoHistory set [PendingAmount] =
            (
            select
                  sum( [TOTCOST])
            from [ACCOUNTSPAYABLE_DETAIL]
            where [RECORD_] is not null
            and [PO_ID] = @Po
            and [CHECKNUMBER] = 0
            and [PAID_DATE] is null
            and [ITEM_] = a.[ITEM_]
            )
      from @PoHistory, [ACCOUNTSPAYABLE_DETAIL] a
      where a.[PO_ID] = [Po]
      and a.[ITEM_] = [Item#]

Open in new window

@Ryan - That will give you INCORRECT Result  !!

Need to set VALUE for ([Po],[Item#]) , your query will give same data for each combination of [Po],[Item#]).

Also note thats very old way of writing SQL code, you should not use that, We should use JOINs.

I have already gave 2 solutions. BOTH should work fine without any issues.
SOLUTION
Avatar of Ryan Chong
Ryan Chong
Flag of Singapore image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Sorry missed the a.item in the inner query but it's inefficient to requery the same tables repeatedly. Simply query once and aggregate.  If you go with the repeat query and join method, just imagine if you had 10000 Item values. While that might be unrealistic for this particular sample problem,  it's important to think about data scaling.

--
UPDATE P
SET P.[PendingAmount] = x.TOTCOST
FROM @PoHistory P
CROSS APPLY 
(
	SELECT
	  SUM([TOTCOST]) [TOTCOST]
	FROM [ACCOUNTSPAYABLE_DETAIL] H
	WHERE H.[PO_ID] = P.[Po] AND H.[ITEM_] = P.[Item#]
	AND [PO_ID] = @Po AND [CHECKNUMBER] = 0 AND [PAID_DATE] IS NULL
)x
--

Open in new window


Apart from that we are only hitting the tables once in the method the group by is also handled internally so that method will really scale well.

We are also using old code and at one point in time we have to upgrade and then this code will not work so you have to change lot of code at that time hence as per my suggestion we should use the latest code methodology.
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
@Author - you can choose from the two of my suggestion-


--

UPDATE P
SET P.[PendingAmount] = x.TOTCOST
FROM @PoHistory P
CROSS APPLY 
(
	SELECT
	  SUM([TOTCOST]) [TOTCOST]
	FROM [ACCOUNTSPAYABLE_DETAIL] H
	WHERE H.[PO_ID] = P.[Po] AND H.[ITEM_] = P.[Item#]
	AND [RECORD_] is not null
	AND [PO_ID] = @Po AND [CHECKNUMBER] = 0 AND [PAID_DATE] IS NULL
)x

--

Open in new window


OR

--

UPDATE P
SET P.[PendingAmount] = x.TOTCOST
FROM @PoHistory P
INNER JOIN 
(
	SELECT
	  SUM([TOTCOST]) [TOTCOST] , H.[PO_ID],H.[ITEM_]
	FROM [ACCOUNTSPAYABLE_DETAIL] H
	WHERE [PO_ID] = @Po AND [CHECKNUMBER] = 0 AND [PAID_DATE] IS NULL 
    AND [RECORD_] is not null
	GROUP BY H.[PO_ID],H.[ITEM_]
)x ON x.[PO_ID] = p.[Po] AND x.[ITEM_] = P.[Item#]

--

Open in new window

Thank you, everyone, for looking at this.