Using user defined function withing Update query in SQL Server - sql-server

Good day!
I've used my user-defined function within an update statement in the following way:
UPDATE Users
SET
CurrentLevel = [dbo].[GetCurrentLevel](id),
Rate = [dbo].[GetRate](id),
LastUpdate = GETUTCDATE()
WHERE id IN (1,2,3)
And it gives me the error:
Subquery returned more than 1 value. This is not permitted when the
subquery follows =, !=, <, <= , >, >= or when the subquery is used as
an expression.
I always get only 1 value whenever I execute these functions outside this Update query.
The following code works as expected
DECLARE id_cursor CURSOR LOCAL FORWARD_ONLY FOR
SELECT id FROM Users
WHERE id IN (1,2,3)
OPEN id_cursor;
FETCH NEXT FROM id_cursor
INTO #id
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #rate FLOAT = [dbo].[GetRate](#id);
UPDATE Users
SET
CurrentLevel = [dbo].[GetCurrentLevel](#id),
Rate = #rate,
LastUpdate = GETUTCDATE()
WHERE id = #id
FETCH NEXT FROM id_cursor
INTO #id
END
I do not understand why am I forced to use a cursor and update 1 row at time.
UPDATE.
This is not a trigger, but a stored procedure.
The user defined-functions both have return type FLOAT, which means that can not return multiple values by definition. Function code:
CREATE FUNCTION [dbo].[GetRate]
(
#userID int
)
RETURNS FLOAT
AS
BEGIN
DECLARE #discount INT = (SELECT TOP 1 [BonusSize] FROM Bonuses WHERE userID = #userID);
DECLARE #rate FLOAT = (SELECT SUM(s.Level * (i.Bonus + #discount))
FROM [Stats] s
JOIN [Orders] v
ON s.Level > 0 AND s.id = v.id AND v.userID = #userID
JOIN (SELECT id, SUM(ISNULL(Bonus,0)) as Bonus FROM Items GROUP BY id) i
ON i.id = v.id)
RETURN ISNULL(#rate/86400.0, 0);
END

Related

How to set multiple output parameters in stored procedures

Is there a way to set multiple output parameters?
For example, in the stored procedure shown here, I wish to get the NUM_OF_ROWS and the TicketNumberz from the same stored procedure.
Since, I am new I don't know how to go about it...
DECLARE #TicketNumberz VARCHAR(15) OUT
DECLARE #NUM_OF_ROWS INT OUT
DECLARE #INIT INT=1 OUT
SET #TicketNumberz = (SELECT TICKETNUMBER
FROM TicketHistory s1
WHERE TICKETTIME IN (SELECT MAX(S2.TICKETTIME)
FROM TicketHistory] S2
WHERE s1.TICKETNUMBER = S2.TICKETNUMBER)
AND CURRENTSTATUS_ANALYST != 'Closed'
AND CURRENTSTATUS_ANALYST = 'Resolved'
AND TICKETTIME < GETDATE() - 5)
-- after getting all the list of ticket numbers, update query follows to update the ticket status to 'Closed'
WHILE (#INIT <= #NUM_OF_ROWS)
BEGIN
INSERT INTO TicketHistory (CURRENTSTATUS_ANALYST, TICKETNUMBER,
PREVIOUSSTATUS_ANALYST, TICKETTIME, FIELD, CREATEDBY)
VALUES ('Closed', #TicketNumberz,
'Resolved', CURRENT_TIMESTAMP, 'Status', 'Auto.User')
END
What this query basically does it, it would fetch all the ''Resolved' tickets which are older than 5 days and had not been 'Closed' automatically. So doing it manually through this stored procedure.
But, I am stuck because of the following error :
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
This is how the db looks like :
I would probably rework the subquery in this but not crucial. It seems that perhaps that table structure is a bit of a challenge here but I think you are looking for something along these lines. This would replace all of the code you posted. There is no need for loops or variables of any kind based on what you posted.
--EDIT--
With the clarification from the OP's comment all that need to happen is add the insert above this select
insert into TicketHistory (CURRENTSTATUS_ANALYST,TICKETNUMBER,PREVIOUSSTATUS_ANALYST,TICKETTIME,FIELD,CREATEDBY)
SELECT 'Closed'
, th.TICKETNUMBER
, 'Resolved'
, CURRENT_TIMESTAMP
, 'Status'
, 'Auto.User'
FROM TicketHistory th
WHERE TICKETTIME IN
(
SELECT MAX(S2.TICKETTIME)
FROM TicketHistory S2
WHERE s1.TICKETNUMBER = S2.TICKETNUMBER
)
--AND CURRENTSTATUS_ANALYST != 'Closed' --there is no value that equals 'Resolved' where it could also equal 'Closed'
AND th.CURRENTSTATUS_ANALYST = 'Resolved'
AND th.TICKETTIME < dateadd(day, -5, GETDATE()) --use dateadd instead of shorthand
Finally, I was able to achieve the desired result with the below code :
--Creating a table variable
declare #TempTable table(ticketnum varchar(50))
--Inserting values in table variable using procedure
insert #TempTable
select TICKETNUMBER
FROM TicketHistory th
WHERE TICKETTIME IN
(
SELECT MAX(S2.TICKETTIME)
FROM TicketHistory S2
WHERE th.TICKETNUMBER = S2.TICKETNUMBER
)
AND th.CURRENTSTATUS_ANALYST = 'Resolved'
AND th.TICKETTIME < dateadd(day, -5, GETDATE())
--Selecting values from table variable
SELECT * from #TempTable
DECLARE #ticket_number varchar(100)
DECLARE cur CURSOR FOR SELECT ticketnum FROM #TempTable
OPEN cur
FETCH NEXT FROM cur INTO #ticket_number
WHILE ##FETCH_STATUS = 0
BEGIN
insert into TicketHistory (CURRENTSTATUS_ANALYST,TICKETNUMBER,PREVIOUSSTATUS_ANALYST,TICKETTIME,FIELD,CREATEDBY)
values('Closed', #ticket_number, 'Resolved', CURRENT_TIMESTAMP, 'Status', 'User.Auto')
FETCH NEXT FROM cur INTO #ticket_number
END
CLOSE cur
DEALLOCATE cur
END

Stored procedure only executes correctly on first execution

I've written this SQL Server stored procedure that inserts records into another table based on the order frequency of customers in another table. It assigns a rank to each customer based on their order frequency. When I create the procedure and execute it for the first time, it works fine and inserts the correct records into the table. But when I clear the table and try to execute the procedure again, no records are added. I have to delete the procedure, restart SSMS, and create the procedure again for it to work correctly again.
Here is the procedure:
create procedure TopKCustomer (#CustRank decimal(11,0))
as
declare CustCursor cursor local for
select o.CustomerID,c.CustomerName,c.CustomerPostalCode,
count(o.CustomerID) as 'Order Frequency'
from (Customer_T c join Order_T o on c.CustomerID=o.CustomerID)
group by o.CustomerID,c.CustomerName,c.CustomerPostalCode
order by [Order Frequency] desc;
declare #PrevOrderFreq float;
declare #CurrOrderFreq float;
declare #CurrRank decimal(11,0);
declare #CurrCustID decimal(11,0);
declare #CurrCustName varchar(25);
declare #CurrCustPostCode varchar(10);
begin
set #PrevOrderFreq = 0;
set #CurrOrderFreq = 0;
set #CurrRank = 0;
set #CurrCustID = 0;
set #CurrCustName = '';
set #CurrCustPostCode = '';
open CustCursor;
while ##FETCH_STATUS = 0
begin
fetch next from CustCursor into #CurrCustID, #CurrCustName, #CurrCustPostCode, #CurrOrderFreq;
if #CurrOrderFreq <> #PrevOrderFreq
begin
set #CurrRank = (#CurrRank + 1);
if #CurrRank > #CustRank
begin
break;
end
end
insert into TopKCustomer_T
values (#CurrCustID, #CurrCustName, #CurrCustPostCode, #CurrRank, getdate());
set #PrevOrderFreq = #CurrOrderFreq;
end
close CustCursor;
deallocate CustCursor;
end
Here are the tables I'm working with:
Customer_T (CustomerID, CustomerName, CustomerAddress, CustomerCity, CustomerState, CustomerPostalCode)
Order_T (OrderID, CustomerID, OrderDate)
TopKCustomer (CustomerID, CustomerName, CustomerPostalCode, CRank, RankGenerateDate)
I think the problem is
while ##FETCH_STATUS = 0
This will be result of the previous fetch (in other words the fetch from the previous execution of your stored procedure, not what you want).
The usual way I wrote cursor loops is
while 1 =1
begin
fetch next from c into ...
if ##fetch_status != 0 break
...
end
There's no sample data or table structure so I don't know what your data looks like. Below is what I think you want. The inner query count the order per customer. The outer query rank them.
SELECT *
, DENSE_RANK() OVER(PARTITION BY CustomerID ORDER BY OrderFrequency) AS Rnk
FROM (
SELECT *
, COUNT(*) OVER (PARTITION BY o.CustomerID) AS OrderFrequency
FROM Customer_T c
JOIN Order_T o ON c.CustomerID = o.CustomerID
) a

Subquery returned more than 1 value. this is not permitted when the subquery follows = or when the subquery is used as an expression

I want to update on my 'MakinelerVeParcalar' table with this query ;
UPDATE MakinelerVeParcalar SET Durum = 'Montaj' WHERE ID = 161
And I got this error;
Msg 512, Level 16, State 1, Procedure trgSureUpdate, Line 31 [Batch Start Line 0]
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
My trgSureUpdate(Trigger)
ALTER TRIGGER [dbo].[trgSureUpdate]
ON [dbo].[MakinelerVeParcalar]
AFTER UPDATE
AS
BEGIN
DECLARE #count INT
DECLARE #idinserted INT
DECLARE #duruminserted VARCHAR(50)
DECLARE #max INT
DECLARE #iddeleted INT
DECLARE #durumdeleted VARCHAR(50)
DECLARE #datediff INT
DECLARE #durumbilgisi varchar(50)
DECLARE #sureinserted INT
DECLARE #suredeleted INT
DECLARE #diffdate INT
SELECT #idinserted = ID from inserted <-- Line 31
SELECT #duruminserted = Durum from inserted
SELECT #iddeleted = ID from deleted
SELECT #durumdeleted = Durum from deleted
SET #count = (SELECT count(*) FROM Sure WHERE ID = #idinserted and Asama = #duruminserted)
SET #max = (SELECT max(SiraNo) FROM Sure WHERE ID = #idinserted)
SET #durumbilgisi = (SELECT DurumBilgisi FROM DurumBilgisi WHERE ID = #idinserted)
SET #sureinserted = (SELECT Sure FROM Sure WHERE ID = #idinserted and Asama = #duruminserted)
SET #suredeleted = (SELECT Sure FROM Sure WHERE ID = #iddeleted and Asama = #durumdeleted)
IF #duruminserted != #durumdeleted
BEGIN
IF #durumbilgisi != 'Bitti'
BEGIN
UPDATE Sure Set Cikis = GETDATE() WHERE Asama = #durumdeleted and ID = #idinserted and SiraNo = #max
SET #diffdate = DATEDIFF (SECOND,(SELECT Giris FROM Sure WHERE ID = #idinserted and SiraNo = #max),(SELECT Cikis FROM Sure WHERE ID = #idinserted and SiraNo = #max))
UPDATE Sure SET Sure = (#diffdate) WHERE ID = #idinserted and SiraNo = #max
END
INSERT INTO Sure (ID,Asama,Giris,Cikis,Sure,SiraNo) VALUES(#idinserted,#duruminserted,GETDATE(),NULL,0,(#max+1))
UPDATE DurumBilgisi SET DurumBilgisi = 'Devam Ediyor' WHERE ID = #idinserted
END
END
I think you might be confused on the line numbers. You have this marked as line 31, but it will NOT throw your error even if there are multiple rows on INSERTED:
SELECT #idinserted = ID from inserted
However, this WILL throw your error if the SELECT returns more than 1 row:
SET #durumbilgisi = (SELECT DurumBilgisi FROM DurumBilgisi WHERE ID = #idinserted)
There are differences between the select #var = col from table syntax and the set #var = (select col from table) syntax. You need to examine the SET queries.

Update table Where IN shows Error Subquery returned more than 1 value

I have the stored proc as follows, it always shows the following error whenever I execute it:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Here's the stored proc code:
DECLARE #Wishlist_AutoID VARCHAR(MAX) = (SELECT Wishlist_AutoID FROM ecommerce.ShoppingCartItem WHERE AutoID = #CartItem_AutoID)
DECLARE #Fulfiller_AutoID BIGINT = (SELECT a.Member_AutoID FROM ecommerce.ShoppingCart a INNER JOIN ecommerce.ShoppingCartItem bON a.AutoID = b.ShoppingCart_AutoID)
UPDATE ecommerce.WishList
SET isFulfilled = 1, FulfilledOn = GETDATE(), FulfilledBy = #Fulfiller_AutoID
WHERE AutoID IN (
SELECT data FROM dbo.Split(#Wishlist_AutoID, ';')
)
SET #Result = ##ROWCOUNT
RETURN #Result
One of you first two variable assignments is the problem:
DECLARE #Wishlist_AutoID VARCHAR(MAX) = (SELECT Wishlist_AutoID FROM ecommerce.ShoppingCartItem
WHERE AutoID = #CartItem_AutoID)
OR
DECLARE #Fulfiller_AutoID BIGINT = (SELECT a.Member_AutoID FROM ecommerce.ShoppingCart a
INNER JOIN ecommerce.ShoppingCartItem b
ON a.AutoID = b.ShoppingCart_AutoID)
These queries could return more than one row, and you can't assign multiple rows to a scaler variable.
Given their subsequent usage, I would say it is the second assignment (#Fulfiller_AutoID ).
Most likely, in either of the lines;
DECLARE #Wishlist_AutoID VARCHAR(MAX) = (
SELECT Wishlist_AutoID
FROM ecommerce.ShoppingCartItem
WHERE AutoID = #CartItem_AutoID)
DECLARE #Fulfiller_AutoID BIGINT = (
SELECT a.Member_AutoID FROM ecommerce.ShoppingCart a
INNER JOIN ecommerce.ShoppingCartItem b
ON a.AutoID = b.ShoppingCart_AutoID)
...your query returns more than one row, so the assignment to a single VARCHAR/BIGINT variable is invalid.

SQL Error 512 while making sql job

I am getting this error with the SQL below:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Does someone know how I can solve it?
use character
DECLARE #guild_codex varchar(25)
DECLARE #character_name0 varchar(40)
DECLARE #user_no0 varchar (25), #id varchar (25)
DECLARE #user_no varchar (25), #group_id varchar (25), #amount varchar (25)
DECLARE #free_amount varchar(25), #2mx_Leader varchar(3), #2mx_member varchar (3)
SET #2mx_Leader = 700 SET #2mx_member = 500 SET #id = (SELECT id from
[PC-ID].[Cash].[dbo].[user_cash] where free_amount LIKE 0) SET
#user_no = (SELECT user_no from [PC-ID].[Cash].[dbo].[user_cash]
where free_amount LIKE 0) SET #group_id = (SELECT group_id from
[PC-ID].[Cash].[dbo].[user_cash] where free_amount LIKE 0) SET
#amount = (SELECT amount from [PC-ID].[Cash].[dbo].[user_cash]
where free_amount LIKE 0) SET #free_amount = (SELECT free_amount from
[PC-ID].[Cash].[dbo].[user_cash] where free_amount LIKE 0) SET
#guild_codex = (SELECT guild_code from siege_info where siege_tag LIKE'Y')
SET #character_name0 = (SELECT character_name from guild_char_info
where guild_code LIKE #guild_codex and peerage_code LIKE 0) SET
#user_no0 = (SELECT user_no from user_character where character_name
LIKE #character_name0)
use cash
UPDATE user_cash SET
amount=amount+#2mx_Leader WHERE user_no = #user_no0
Multiple issues with your SQL
To assign values for multiple variables, selecting from the same table, with the same where clause, you are making multiple trips to the DB, while it can be done in one single call, like this:
SELECT
#id = id,
#user_no = user_no,
#group_id = group_id,
#amount = amount,
#free_amount = free_amount
FROM [PC-ID].[Cash].[dbo].[user_cash]
WHERE free_amount LIKE 0
You are using LIKE, which could return multiple rows of data, as stated in your error message. Try using = if you can. Alternately, try executing the Select statements responsible for populating your variables to see if more than one row of data is returned.
Raj

Resources