Create generate random number function in SQL Server - sql-server

I'm trying to create the function in SQL Server. In this function I have generated the random number, but function not generated.
Create function [GetRandomNumber]
(
)
RETURNS bigint
as
Begin
Declare #randomNo int
set #randomNo = (select round(rand(checksum(newid()))*(10001)+50000,0) as [GetRandomNumber])
return #randomNo
End
this is generated in following error:
Invalid use of a side-effecting operator 'newid' within a function.
Msg 443, Level 16, State 1, Procedure GetRandomNumber, Line 8
Invalid use of a side-effecting operator 'rand' within a function.

You can. However, it will require a little bit of extra legwork.
First, you need to create a view, like the one below:
create view dbo.sys_NDF
as
select rand() as [ValueRand], newid() as [ValueGUID],
rand(checksum(newid())) as [SeededRand];
go
The trick is that you cannot call these system functions directly from your UDF, however you can query a view that returns their values. You can later expand it with other functions / columns if need be.
As such, your function starts to look like the following:
Create function [GetRandomNumber]()
RETURNS bigint as begin
return (select round(v.SeededRand * 10001 + 50000, 0) from dbo.sys_NDF v);
end;
go

Create SP instead of function. Because some system function are not allowed in user defined function.
CREATE PROCEDURE [GetRandomNumber]
as
Begin
Declare #randomNo int
set #randomNo = (select round(rand(checksum(newid()))*(10001)+50000,0) as [GetRandomNumber])
return #randomNo
End
GO
DECLARE #returnvalue INT
EXEC #returnvalue = GetRandomNumber
SELECT #returnvalue

Related

SQL Server function error with if condition

I'm still trying to learn an SQL, i made a mistakes but i already search on the internet about the if statements...
I tried to create a simple function to check if the parameter is match the condition..
I have 2 parameters, that will be inputted manually by the users, but i got an error saying
Msg 156, Level 15, State 1, Procedure ufn_calculatebonus, Line 4 [Batch Start Line 1] Incorrect syntax near the keyword 'IF'. Msg 178, Level 15, State 1, Procedure ufn_calculatebonus, Line 10 [Batch Start Line 1] A RETURN statement with a return value cannot be used in this context.
This is the code i've tried to create, i thought i make the IF condition right? After the IF , should have a BEGIN and statements, closing it with END. ??
CREATE FUNCTION Sales.ufn_calculatebonus (#CompanyRevenue int, #OptionalParameter varchar(60))
RETURNS TABLE
AS
IF #CompanyRevenue > 10
BEGIN
SELECT 'INPUT CANNOT BE BIGGER THAN 1000'
END
ELSE
BEGIN
RETURN
(
SELECT * FROM SALES.CUSTBALANCE2 where region=#OptionalParameter or name=#OptionalParameter
);
END
GO
There are 2 distinct types of T-SQL table-valued functions, inline TVF and multi-statement TVF. The body of an inline TVF consists of only of a RETURNS statement with a query specification (not to be confused with a RETURN statement).
Your attempt at a multi-statement table-valued function is invalid for the reasons below.
The body of a multi-statement TVF must be surrounded with BEGIN...END.
A table variable with the returned schema must be declared in the function header.
One cannot return query results with a RETURN statement. Instead, insert results into the table variable declared in the function header end specify RETURN at the end of the function to return the results.
Below is an example of the remediated code. Importantly, note the use of an explicit column list throughout. Don't SELECT * in production code.
CREATE OR ALTER FUNCTION dbo.ufn_calculatebonus (#CompanyRevenue int, #OptionalParameter varchar(60))
RETURNS #BalanceInfo TABLE (CustomerID int, Balance int, ErrorMessage varchar(100))
AS
BEGIN
IF #CompanyRevenue > 10
BEGIN
INSERT INTO #BalanceInfo (ErrorMessage) VALUES('INPUT CANNOT BE BIGGER THAN 1000');
END
ELSE
BEGIN
INSERT INTO #BalanceInfo (CustomerID, Balance) --note ErrorMessage is omitted and will be NULL
SELECT CustomerID, Balance FROM SALES.CUSTBALANCE2 where region=#OptionalParameter or name=#OptionalParameter;
END;
RETURN;
END
GO
A stored procedure is a better fit than a than user-defined function if you need to raise custom errors for parameter validation. Here's a stored procedure example:
CREATE OR ALTER PROCEDURE dbo.usp_calculatebonus (#CompanyRevenue int, #OptionalParameter varchar(60))
AS
IF #CompanyRevenue > 10
BEGIN
THROW 50000, 'INPUT CANNOT BE BIGGER THAN 1000', 16;
END;
SELECT CustomerID, Balance FROM SALES.CUSTBALANCE2 where region=#OptionalParameter or name=#OptionalParameter;
GO

Declare and assign result from stored procedure in one line

Is it possible to declare and assign the result from an sp in one statement?
If we can do,
DECLARE #lastid INTEGER = (SELECT MAX([Id]) FROM [ADVWKS].[dbo].[Account]);
why cant we do the below one?
DECLARE #lastaccid INTEGER = (EXEC sp_GetGlobalVarVal 'LAST_ACCID');
So far you need one statement to declare the variable and one to execute the procedure and assign the variable as return, output, cursor etc. Can we do it in a single statement??
You cannot do the below because it is often the case that the return type for the stored procedure is a table. It would either execute, and run DML statements which wont return anything, or it would return data set. Now what you can do is to build a scalar value function instead of stored procedure and select from that. https://learn.microsoft.com/en-us/sql/t-sql/statements/create-function-transact-sql?view=sql-server-2017
Another possibility is using: https://learn.microsoft.com/en-us/sql/relational-databases/stored-procedures/return-data-from-a-stored-procedure?view=sql-server-2017#returning-data-using-a-return-code, but conceptually per article, this is only used for Return Codes, not really for the variable assignment or populating variables for different types, and do not forget, there is only values between 0 - 4.
Use an OUTPUT parameter instead. This is very simplified, however:
CREATE PROC TEST_SP #I int, #O int OUTPUT AS
SET #O = #I *5;
GO
DECLARE #Var int;
EXEC TEST_SP 1,#Var OUTPUT;
SELECT #Var;
GO
--CLEAN UP
DROP PROC TEST_SP;
You can use OUTPUT Parameters:
This is an example SP where the second variable (#Param_2) is defined as output Parameter
CREATE PROCEDURE [dbo].[MySP]
(
#Param_1 int,
#Param_2 int output
)
AS
BEGIN
SET NOCOUNT ON;
SET #Param_2 = 10 * #Param_1;
END
Now you can call the SP like this:
DECLARE #Value_1 INT = 42;
DECLARE #RetVal INT = 0;
SELECT #RetVal;
EXEC [dbo].[MySP] #Value_1, #Param_2 = #RetVal OUTPUT;
SELECT #RetVal;
The frist time you select #RetVal the value will still be 0. After the execution of the SP, #RetVal will be 420 (10 * 42 calcualted inside the SP):
-----------
0
(1 row affected)
-----------
420
(1 row affected)
TLDR: No :)

SQL server Function and procedure regarding the linking of a table output to scalar procedure

This what I have so far individually all for sections work fine, I just cant figure out how to combine them properly.
Table function and procedure
USE [MENUdb]
GO
CREATE Function [dbo].[func_GetMenuItemsForMenu]
(
#MENUID NVARCHAR (50)
)
RETURNS TABLE
AS
RETURN
(
SELECT MenuItem.MenuID,MenuItem.MenuItemID,MenuItem.MenuItemTitle FROM MenuItem,Menu
WHERE Menu.MenuID = #MENUID
AND MenuItem.MenuID = Menu.MenuID)
GO
USE [MENUdb]
GO
ALTER Procedure [dbo].[sp_GetMenuItemsForMenu]
(
#ENTER_MENUID int
)
AS
BEGIN
SELECT * FROM func_GetMenuItemsForMenu (#ENTER_MENUID)
END
Scalar function and procedure
USE [MENUdb]
ALTER FUNCTION [dbo].[func_GetMenuItemDescriptionForMenuItemID]
(
#MENUITEMID int
)
RETURNS nvarchar(MAX)
AS
BEGIN
RETURN
(
SELECT MenuItem.MenuItemTitle +' ' + MenuItem.MenuItemDescriptionText FROM MenuItem WHERE MenuItemID = #MENUITEMID
)
END
USE [MENUdb]
GO
ALTER Procedure [dbo].[sp_GetMenuItemDescriptionForMenuItemID]
(
#ENTER_MENUITEMID int
)
AS
BEGIN
SELECT dbo.func_GetMenuItemDescriptionForMenuItemID (#ENTER_MENUITEMID)
END
Individually they work fine exactly as they should besides the fact that I am not sure how to output if there are multiple rows that fit the input for the scalar
My main issue is that I can quite figure out how to get the result of the Table function specifically the MenuItemID column to work as the input of the Scalar function
what should happen is this, say there are 3 items on menu 1, I enter 1 in the initial execution and it returns the 3 items IDs and Names in table form, how do I pass the IDs in the MenuItemID column to the next function?
Coding is not my strong point so im probably missing something very simple...

Why can't I run INSERT EXEC on a table variable in a T-SQL function?

My function looks like this:
CREATE FUNCTION fn_FileSys_DirExists(#dirName AS nvarchar(260))
RETURNS bit
AS
BEGIN
DECLARE #dirExists int
DECLARE #fileResults TABLE
(
file_exists int,
file_is_a_directory int,
parent_directory_exists int
)
INSERT #fileResults (file_exists, file_is_a_directory, parent_directory_exists)
EXEC master.dbo.xp_fileexist #dirName
SELECT #dirExists = file_is_a_directory FROM #fileResults
RETURN #dirExists
END
When I try and execute the above SQL, I get the following error:
Invalid use of a side-effecting operator 'INSERT EXEC' within a
function.
I thought operations on a table variable in a function weren't considered side effecting operations?
INSERT ... EXEC is a side effecting operator because it ends up creating a temporary table behind the scenes.
This is behind the parameter table scan shown in the execution plan for this dbfiddle
See The Hidden Costs of INSERT EXEC for more about that.
You'll be best off writing a CLR function to do this.

must declare scalar variable error in Powerbuilder

I'm facing this error " must declare the scalar variable #return " in PowerBuilder 9 running on SQL server 14. When I'm executing the stored procedure using the SQL management studio it is returning 10000 as expected. But while calling this SP from PowerBuilder I'm facing the error. Any suggestions are appreciated. Thanks
Function in PowerBuilder code:
Declare sp_v procedure for
#return = proc_v_sp
#eid = :p_eid,
#year = :p_year,
#bid = :p_bid,
#hid = :p_hid
using sqlca;
Execute sp_v;
IF SQLCA.SQLCode <> 0 THEN
lReturn = SQLCA.SQLCode
ELSE
FETCH sp_v INTO :lReturn;
END IF
CLOSE sp_v;
In SQL SERVER SP:
Alter procedure proc_v_sp
#eid int,
#year int,
#bid varchar(8),
#hid char(3)
As
Begin
Declare #count int,
Declare..............
..........ignoring as it is long SP...........
Select #count = count(*)
from sy_e
where sy_e_eid = #eid and sy_e_year= #year
IF #count >0
RETURN 20000
ELSE
RETURN 10000
END
Looking at the documentation, I don't see anything about how to get a RETURN value back from an executed stored procedure. The documentation lists the syntax for the SP declaration in PB as...
DECLARE logical_procedure_name PROCEDURE FOR
SQL_Server_procedure_name
#Param1 = value1, #Param2 = value2,
#Param3 = value3 OUTPUT,
{USING transaction_object} ;
So that's why you're getting the syntax error. It's just not expecting #return there. If you can change the stored procedure, then you should be able to use an OUTPUT parameter. After a bit of googling, it looks like you would still have to use FETCH after the EXECUTE to get the variable specified for the output parameter populated.
I came back to this once I had PB in front of me because I was curious if it was possibles. After a bit of experimentation and looking at the MSDN docs for RETURN, I was able to get the return value populated in the returnValue variable using the code below.
long returnValue
DECLARE sp_test PROCEDURE FOR
#return_status = sp_test_return
USING SQLCA;
EXECUTE sp_test;
FETCH sp_test INTO :returnValue;
Here's the stored procedure.
CREATE PROCEDURE [dbo].[sp_test_return]
AS
RETURN 159
GO
You're making this all way too hard...
Change your RETURN to SELECT, and use a stored procedure datawindow. You can then rip out all that code, and replace it with one line.
dw.retrieve( args )
And your return value will be dw.getItemNumber( 1, "return_status")
-Paul-
I don't have sample code.
But it's super easy... Your SP needs to return a result set instead of a return value - even if that result set is a single value on a single row.
Change the RETURN to SELECT. That returns a result set.
Now, create a datawindow and select Stored Procedure as the datasource. Then select your sp as the source. Test it by providing the values for arguments and seeing if it returns the result you're looking for.
From here, it's just PB code.
datastore myDW
myDW = create datastore
myDW.setTransObject( SQLCA )
myDW.retrieve( args... )
theResult = myDW.getItemNumber( 1, "return_status" )

Resources