stored procedure returning value - sql-server

using this code :
ALTER PROCEDURE [dbo].[get](#i int)
AS
BEGIN
declare #ADate datetime
select #ADate = ADate
from table
where i=#i
and DateDiff(day ,getDate(), aDate ) > 0
and aDate is not null
order by aDate asc
return select #ADAte
END
this returns 0 (or system 0 date time, which is not the desired result from the data base).
execute code
Declare #res datetime
exec #res = get 3
print #res
why?

Stored Procedures in SQL Server can only RETURN integers. If you need to return anything other than a single integer, then you should use one of these methods (some explained by the previous answers):
Use a SELECT in your procedure
Use an OUTPUT Parameter
Use a User Defined Function instead

There isn't any need to declare a variable and assign a value to it. Just return the select statement.
ALTER PROCEDURE [dbo].[get](#i int)
AS
BEGIN
select ADate
from table
where i=#i
and DateDiff(day ,getDate(), aDate ) > 0
and aDate is not null
order by aDate asc
END
Although you should be aware that depending on your data this may return more than one value.
EDIT
If you want to you could do it this way:
ALTER PROCEDURE [dbo].[get](#i int, #date datetime output)
AS
BEGIN
select #date = ADate
from table
where i=#i
and DateDiff(day ,getDate(), aDate ) > 0
and aDate is not null
order by aDate asc
END
And then you can use it like so:
Declare #res datetime
exec get 3, #res
print #res

You should select the value:
select #OADate
Your value will be the first value in the first row on the first resultset.

Have a look at CREATE PROCEDURE
you need to use the OUTPUT clause
**OUTPUT**
Indicates that the parameter is a return parameter. The value of this option can be returned to EXEC[UTE]. Use OUTPUT parameters to return information to the calling procedure.
Also, returning a single value seems like it is calling for a USER DEFINED SCALAR FUNCTION, rather than a STORED PROCEDURE

Related

T-SQL : CREATE FUNCTION must be the only statement in batch [duplicate]

I'm getting this error from the function:
CREATE FUNCTION getLavel(#id int ,#lavel char)
RETURNS date
BEGIN
DECLARE #date date
select #date = (select authorization_date from Authorized WHERE diver_number = #id and #lavel =level_name)
return #date
END
GO
What can be the reason?
Ty very much.
The function needs to be either the only function in the query window OR the only statement in the batch. If there are more statements in the query window, you can make it the only one "in the batch" by surrounding it with GO's.
e.g.
GO
CREATE FUNCTION getLavel(#id int ,#lavel char)
RETURNS date
BEGIN
DECLARE #date date
select #date = (select authorization_date from Authorized WHERE diver_number = #id and #lavel =level_name)
return #date
END
GO
Turn this into an inline table valued function. This will perform better than the scalar function. Also, you should NOT use the default sizes for character datatypes. Do you know what the default length for a char is? Did you know that it can vary based on usage?
CREATE FUNCTION getLavel
(
#id int
, #lavel char --You need to define the length instead of the default length
)
RETURNS table
return
select authorization_date
from Authorized
WHERE diver_number = #id
and #lavel = level_name
GO
You need to add RETURN before the END statement
That should fix your issue, that's what fixed mine. :D
Make sure that this statement is the only the only sql in your query window before you execute it.
Or you can highlight the function declaration and execute
What solved it for me, was that I was trying to create the function inside of a transaction context - that doesn't make sense from a SQL Server point of view. Transactions are for data, not functions.
Take the CREATE FUNCTION statement out of the transaction, then wrap it in GO's
CREATE FUNCTION CalculateAge(#DOB DATE)
RETURNS INT
AS
BEGIN
DECLARE #Age INT
SET #DOB='08/12/1990'
SET #Age =DATEDIFF(YEAR,#DOB,GETDATE()) -
CASE
WHEN (MONTH (#DOB)> MONTH (GETDATE ())) OR
(MONTH (#DOB)= MONTH (GETDATE ()) AND DAY (#DOB) >DAY (GETDATE ()))
THEN 1
ELSE 0
END
SELECT #Age
END
The Error is given to you in only query Page But if you execute the query then it will successfully execute.
CREATE FUNCTION getLavel(#id int ,#lavel char)
RETURNS date
BEGIN
DECLARE #date date
select #date = (select authorization_date from Authorized WHERE diver_number = #id and #lavel = level_name)
return #date
END
GO

SQL Server stored procedure oDate as a parameter not recognized

How can we pass the date (data type DateTime) in the execution command to run a stored procedure?
Here is the code snippet.
ALTER PROCEDURE [dbo].[datefiltered]
#months_margin int,
#oDate datetime
AS
BEGIN
SELECT *
FROM dbo.table20
WHERE date = oDate
-- more code...
END
I am trying to execute this stored procedure using GETDATE() function or even pass date and time as a string but it's not working.
exec datefiltered 23 getDate()
As you want to apply date filter, you don't need to pass datetime value. You can convert to DATE datatype for equality.
select * from dbo.table20
where date = CAST(#oDate AS DATE)
Also, if you are just passing GETDATE() as default, you can keep getdate as default value, as given below:
Alter procedure [dbo].[datefiltered]
#months_margin int,
#oDate datetime = null
AS
Begin
IF #oDate IS NULL
BEGIN
SET #oDate = CAST(GETDATE() AS DATE)
END
When you call the procedure with default value, you don't need to pass parameter value for it.
exec datefiltered 23 -- getdate() filter is applied automatically
ALTER PROCEDURE [dbo].[datefiltered]
#months_margin int,
#oDate datetime
AS
BEGIN
SELECT *
FROM dbo.table20
WHERE date = CAST(#oDate AS DATE)
-- more code...
END
Executing this stored procedure:
exec datefiltered 23, '2010-02-30'

Apply OFFSET and FETCH NEXT to an existing stored procedure

I have an existing stored procedure and I would like to apply the concept of paging by using OFFSET and FETCH NEXT.
However since this stored procedure already exists, and is called from other sources, I don't want to break it. I have added 2 optional parameters called #PageNumber INT = NULL and #NumberOfRecordsToRetrieve INT = NULL. I would like to know how to incorporate the logic into my query inside the stored procedure when these values are not supplied.
CREATE PROCEDURE TEST_PROCEDURE
#Id INT,
#PageNumber INT = NULL,
#NumberOfRecordsToRetrieve INT = null
AS
BEGIN
SET NOCOUNT ON;
DECLARE #offsetRows INT, #nextRows INT, #maxCount INT
IF(#PageNumber IS NOT NULL AND #NumberOfRecordsToRetrieve IS NOT NULL)
BEGIN
SET #offsetRows = (#PageNumber - 1) * #NumberOfRecordsToRetrieve;
SET #nextRows = #NumberOfRecordsToRetrieve;
END
ELSE
BEGIN
SET #offsetRows = 0;
SET #nextRows = 0;
END
SELECT
Id,
Column2,
Column3
FROM
ABCCustomers
WHERE
Id = #Id
UNION
SELECT
Id,
Column2,
Column3
FROM
DEFCustomers
WHERE
Id = #Id
ORDER BY
Column2
-- this section needs to be applied only if the parameters have values
OFFSET #offsetRows ROWS
FETCH NEXT #nextRows ROWS ONLY
END
The offset and fetch next needs to be applied only when there is a value or else I will get an error. How do I solve this?
Simple, but perfectly acceptable:
IF #PageNumber IS NULL
{Do query without OFFSET..FETCH}
ELSE
{Do query with OFFSET..FETCH}
If you do not want to double your SQL statment: COALESCE is a alternative.
select id,
name
from user
order by id
offset COALESCE(#offset,0) rows
fetch next COALESCE(#pageSize,2147483647) rows only
Like this answer:
Using OFFSET-FETCH, how to default number of rows to "all rows"?

SQL server Function - Take column name as input parameter

I need to write a SQL function to return column specific values, so I am passing the column name as a parameter to SQL-function to return its corresponding value. Here is the sample function
CREATE FUNCTION GETDATETIME(#columnName VARCHAR(100))
RETURNS DATETIME
AS
BEGIN
RETURN (SELECT TOP 1.#columnName FROM TEST_TABLE )
END
GO
The above function seems to be straight forward, but it not working as expected.
And when I execute the function
SELECT dbo.GETDATETIME('DATETIMECOLUMNNAME')
I am getting this error:
Conversion failed when converting date and/or time from character string.
Can someone help me to identify the issue?
For that you need to write dynamic sql. But Functions won't support execute statement.
So you need to write multiple If conditions for each column.
CREATE FUNCTION GETDATETIME(#columnName VARCHAR(100))
RETURNS DATETIME
AS
BEGIN
DECLARE #RESULT DATETIME;
IF (#columnName = 'ABC')
Begin
SELECT TOP 1 #RESULT = [ABC] FROM TEST_TABLE
END
ELSE IF (#columnName = 'DEF')
Begin
SELECT TOP 1 #RESULT = [DEF] FROM TEST_TABLE
END
ELSE IF (#columnName = 'GHI')
Begin
SELECT TOP 1 #RESULT = [GHI] FROM TEST_TABLE
END
RETURN #RESULT
END
GO
Edit 2:
If your column always return Datetime, then you can do like below.
CREATE TABLE A_DUM (ID INT, STARTDATE DATETIME, ENDDATE DATETIME, MIDDLEDATE DATETIME)
INSERT INTO A_DUM
SELECT 1, '2019-07-24 11:35:58.910', '2019-07-28 11:35:58.910', '2019-07-26 11:35:58.910'
UNION ALL
SELECT 2, '2019-07-29 11:35:58.910', '2019-08-01 11:35:58.910', '2019-07-24 11:35:58.910'
And your function like below
CREATE FUNCTION GETDATETIME(#columnName VARCHAR(100))
RETURNS DATETIME
AS
BEGIN
DECLARE #RESULT DATETIME;
SELECT TOP 1 #RESULT = CAST(PROP AS DATETIME)
FROM A_DUM
UNPIVOT
(
PROP FOR VAL IN (STARTDATE, ENDDATE,MIDDLEDATE)
)UP
WHERE VAL = #columnName
RETURN #RESULT
END
GO
There's a workaround to this, similar to #Shakeer's answer - if you are attempting to GROUP BY or perform a WHERE on a column name, then you can just use a CASE statement to create a clause to match on specific column names (if you know them).
Obviously this doesn't work very well if you have many columns to hard-code, but at least it's a way to achieve the general idea.
E.g. with WHERE clause:
WHERE
(CASE
WHEN #columnname = 'FirstColumn' THEN FirstColumnCondition
WHEN #columnname = 'SecondColumn' THEN SecondColumnCondition
ELSE SomeOtherColumnCondition
END)
Or with GROUP BY:
GROUP BY
(CASE
WHEN #columnname = 'FirstColumn' THEN FirstColumnGroup
WHEN #columnname = 'SecondColumn' THEN SecondColumnGroup
ELSE SomeOtherColumnGroup
END)
No you cannot use dynamic sql in functions in SQL. Please check this link for more info link.
So it is not possible to achieve this by any function, yes you may use stored procedures with output parameter for same.
You may find this link for reference link.

Looking for a General "Minimum" User Defined Function

I created the following function to simplify a piece of particularly complex code.
CREATE FUNCTION [dbo].[DSGetMinimumInt] (#First INT, #Second INT)
RETURNS INT
AS
BEGIN
IF #First < #Second
RETURN #First
RETURN #Second
END
However, it only works for the INT datatype. I know I could create one for numeric and possibly for Varchar and Datetime.
Is it possible to create one master "Minimum" function to deal with them all? Has anyone done this?
I've Googled it, but come up empty.
here is a basic one you can work with, I'd be careful using this in queries, as it will slow them down in proportion to the number of rows it is used on:
CREATE FUNCTION [dbo].[DSGetMinimum] (#First sql_variant, #Second sql_variant)
RETURNS varchar(8000)
AS
BEGIN
DECLARE #Value varchar(8000)
IF SQL_VARIANT_PROPERTY(#First,'BaseType')=SQL_VARIANT_PROPERTY(#Second,'BaseType')
OR #First IS NULL OR #Second IS NULL
BEGIN
IF SQL_VARIANT_PROPERTY(#First,'BaseType')='datetime'
BEGIN
IF CONVERT(datetime,#First)<CONVERT(datetime,#Second)
BEGIN
SET #Value=CONVERT(char(23),#First,121)
END
ELSE
BEGIN
SET #Value=CONVERT(char(23),#Second,121)
END
END --IF datetime
ELSE
BEGIN
IF #First < #Second
SET #Value=CONVERT(varchar(8000),#First)
ELSE
SET #Value=CONVERT(varchar(8000),#Second)
END
END --IF types the same
RETURN #Value
END
GO
EDIT
Test Code:
DECLARE #D1 datetime , #D2 datetime
DECLARE #I1 int , #I2 int
DECLARE #V1 varchar(5) , #V2 varchar(5)
SELECT #D1='1/1/2010', #D2='1/2/2010'
,#I1=5 , #I2=999
,#V1='abc' , #V2='xyz'
PRINT dbo.DSGetMinimumInt(#D1,#D2)
PRINT dbo.DSGetMinimumInt(#I1,#I2)
PRINT dbo.DSGetMinimumInt(#V1,#V2)
Test Output:
2010-01-01 00:00:00.000
5
abc
If you are going to use this in a query, I would just use an inline CASE statement, which would be MUCH faster then the UDF:
CASE
WHEN #valueAnyType1<#ValueAnyType2 THEN #valueAnyType1
ELSE #ValueAnyType2
END
you can add protections for NULL if necessary:
CASE
WHEN #valueAnyType1<=ISNULL(#ValueAnyType2,#valueAnyType1) THEN #valueAnyType1
ELSE #ValueAnyType2
END
All major databases except SQL Server support LEAST and GREATEST which do what you want.
In SQL Server, you can emulate it this way:
WITH q (col1, col2) AS
(
SELECT 'test1', 'test2'
UNION ALL
SELECT 'test3', 'test4'
)
SELECT (
SELECT MIN(col)
FROM (
SELECT col1 AS col
UNION ALL
SELECT col2
) qa
)
FROM q
, though it will be a little bit less efficient than a UDF.
Azure SQL DB (and future SQL Server versions) now supports GREATEST/LEAST:
GREATEST
LEAST

Resources