I have this one: (updated)
IF OBJECT_ID (N'dbo.fn_getProductCatPurchased', N'IF') IS NOT NULL
DROP FUNCTION [dbo].fn_getProductCatPurchased;
GO
then the function starts:
CREATE FUNCTION [dbo].fn_getProductCatPurchased
(
#Custno varchar(100),
#PriceType varchar(100)
)
RETURNS int
AS
BEGIN
DECLARE #groups int;
SELECT #groups = COUNT(DISTINCT(prodcat))
FROM SALES
WHERE custno = #Custno
AND pricetype=#PriceType
IF (#group IS NULL)
SET #group = 0;
RETURN #group;
END;
GO
When I try to save the function an error was thrown:
Incorrect syntax near fn_getProductCatPurchased
What am I doing wrong?
Not sure if this is the cause of your error, but it's definitely a problem.
You are declaring a variable called #groups:
DECLARE #groups int;
but proceed to use #group without an s instead:
IF (#group IS NULL)
SET #group = 0;
RETURN #group;
Related
I am not expert in functions. Inherited the following function which is very slow
ALTER FUNCTION [dbo].[fn_Diagnosed]
( #clientId As int)
RETURNS NVARCHAR(10)
AS
BEGIN
DECLARE #result int;
Declare #return nvarchar(10);
set #result = (SELECT COUNT(*)
FROM dbo.AdditionalInfo
WHERE dbo.AdditionalInfo.Type = 'Diagnosed' and ClientId = #ClientId);
IF #result > 0
set #return = 'Yes'
ELSE
set #return = 'No';
return #return;
END
Is this the right way to write a function?
Your function looks fine. An index is not automatically created on a foreign key constraint. So, you should explicitly add an index, like this
CREATE INDEX ClientAdditionalInfo_ClientID
ON [dbo].[ClientAdditionalInfo]
(ClientID)
INCLUDE ([Type])
I created a function like this:
CREATE FUNCTION dbo.HashCheeseName (#CheeseName NVARCHAR(40))
RETURNS VARCHAR(40)
AS BEGIN
DECLARE #Salt VARCHAR(25)
DECLARE #CheeseName NVARCHAR(40)
DECLARE #output VARCHAR(40)
SET #Salt = '123abc11aa'
SET #output = HASHBYTES('SHA2_256', CAST(#CheeseName as VARCHAR(40)) + #Salt)
RETURN #output
END
;
When I just run
SELECT HASHBYTES('SHA2_256', CAST('SwissCheese' as VARCHAR(40)) + #Salt)
I get an expected result like 0xF456D41144584064AC5456B7E3...
However, when I run the function in a query
SELECT dbo.HashCheeseName('SwissCheese')
I get a result like this: h:Mó!yýŠù’p» ªu_aøP¾æhw
Any ideas on why it would result in something like this? At first sight it looks like a conversion issue, but I don't see the problem
What you are doing there isn't the same. HASHBYTES returns a varbinary (Hashbytes (Transact-SQL) - Return Values) where as your function is returning a varchar. Those are different datatypes. As a result, the last line of your function is effectively:
SET #output = CONVERT(varchar(40),HASHBYTES('SHA2_256', CAST(#CheeseName as VARCHAR(40)) + #Salt));
The varchar representation of a varbinary will not be the same. Either return a varbinary in your function, or your test SELECT with a CONVERT to a varchar(40).
Edit: To confirm, the solution is to simply change the return type of your function and variable:
CREATE FUNCTION dbo.HashCheeseName (#CheeseName NVARCHAR(40))
RETURNS varbinary(8000)
AS BEGIN
DECLARE #Salt VARCHAR(25);
DECLARE #CheeseName NVARCHAR(40);
DECLARE #output varbinary(8000) ;
SET #Salt = '123abc11aa';
SET #output = HASHBYTES('SHA2_256', CAST(#CheeseName as VARCHAR(40)) + #Salt);
RETURN #output;
END
I written the following function.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Create FUNCTION NameFunction
(
#eid int
)
RETURNS varchar
AS
BEGIN
Declare #logid varchar(50);
SELECT #logid = E.LoginId from HumanResources.Employee As E
where E.BusinessEntityID = #eid
RETURN #logid
END
GO
When I am executing it is showing result as a.
But expected result is adventure-works\terri0
Where I did the mistake here. Only first character coming. Need to change any thing?
Change your RETURN type to include a length, at this point it is just returning 1 character:
RETURNS varchar(100)
Full code:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Create FUNCTION NameFunction
(
#eid int
)
RETURNS varchar(100) -- or whatever length you need
AS
BEGIN
Declare #logid varchar(50);
SELECT #logid = E.LoginId from HumanResources.Employee As E
where E.BusinessEntityID = #eid
RETURN #logid
END
GO
RETURNS varchar should be RETURNS varchar(50).
varchar without a length specified is interpreted as varchar(1) in this context (and as varchar(30) in the context of a CAST).
BTW: Scalar UDFs that do data access can be performance killers. You might want to consider at least rewriting this as an inline TVF so that the optimiser has more options.
I having problems with this function, seems like #idUsuario and #passCorrecto aren't getting any value, so, when I use this variables in the where clause I'm not getting any result data.
ALTER FUNCTION [dbo].[login](#usuario varchar(20), #password varchar(20))
RETURNS #info TABLE (nombre varchar(70) not null, tipo varchar(30) not null)
AS
BEGIN
DECLARE #idUsuario int = dbo.usuarioExiste(#usuario)
DECLARE #passCorrecto bit = dbo.passwordCorrecto(#idUsuario, #password)
INSERT #info
SELECT
usuarios.nombreUsuario, tiposUsuarios.tipoUsuario
FROM
usuarios
LEFT JOIN
tiposUsuarios
ON
usuarios.idTipoUsuario = tiposUsuarios.idTipoUsuario
WHERE
usuarios.idUsuario = #idUsuario and
usuarios.estatus = 'ACTIVO' and
#passCorrecto = 1
RETURN
END
What am I doing wrong?
EDIT
Here are the function used above:
ALTER FUNCTION [dbo].[usuarioExiste]
(
#usuario varchar(20)
)
RETURNS integer
AS
BEGIN
DECLARE #idUsuario integer
SELECT
#idUsuario = idUsuario
FROM
usuarios
WHERE
usuario = #usuario
if #idUsuario is null begin
set #idUsuario = 0
end
RETURN #idUsuario
END
ALTER FUNCTION [dbo].[passwordCorrecto]
(
#usuario varchar(20),
#password varchar(20)
)
RETURNS bit
AS
BEGIN
DECLARE #esCorrecto bit
SELECT
#esCorrecto = case when password = #password then 1 else 0 end
FROM
usuarios
WHERE
usuario = #usuario
RETURN #esCorrecto
END
EDIT 2
As suggested by Beth, I created new functions that returns the values that I need like this:
CREATE FUNCTION [dbo].[usuarioExisteTest]
(
#usuario varchar(20)
)
RETURNS int
AS
BEGIN
declare #idUsuario int;
set #idUsuario = 1;
return (#idUsuario);
END;
By doing this I'm getting the data I need, am I setting the values to return the wrong way in the original functions?
DECLARE #idUsuario integer
SELECT
#idUsuario = idUsuario
FROM
usuarios
WHERE
usuario = #usuario
I know SQL Server 2008 supports the combined DECLARE/assign, but have you tried separating them?
DECLARE #idUsuario int
SET idUsuario = dbo.usuarioExiste(#usuario)
DECLARE #passCorrecto bit
SET passCorrecto = dbo.passwordCorrecto(#idUsuario, #password)
From BOL
Assigns a value to the variable
in-line. The value can be a constant
or an expression, but it must either
match the variable declaration type or
be implicitly convertible to that
type.
Of course, a udf is an expression, but is it possible there is some anomaly when used in DECLARE (like when you use a udf in CHECK constraint: it's not reliable). Or DECLARE ins a udf for some reason.
Please humour me. Try it.
Also, you have no "failsafe" inside dbo.passwordCorrecto which means it could return NULL which will always evaluate to false in the outer udf.
try printing the values of the variables after you declare them. If they aren't set correctly, try calling the functions in a new query window instead of within [dbo].[login]. That should help identify the problem.
I've found a solution, seem like using select #var = some_value doesn't work well. See this:
A SELECT statement that contains a variable assignment cannot be used to also perform typical result set retrieval operations.
These are the fixed functions:
usuarioExiste
CREATE FUNCTION [dbo].[usuarioExiste]
(
#usuario varchar(20)
)
RETURNS int
AS
BEGIN
declare #idUsuario int = 0;
set #idUsuario = (
select
idUsuario
from
usuarios
where
usuario = #usuario);
if #idUsuario is null begin
set #idUsuario = 0;
end;
return (#idUsuario);
END;
passwordCorrecto
CREATE FUNCTION [dbo].[passwordCorrecto]
(
#idUsuario int,
#password varchar(20)
)
RETURNS bit
AS
BEGIN
declare #esCorrecto bit = 'false';
set #esCorrecto = (
select
case when password = #password then 'true' else 'false' end
from
usuarios
where
usuarios.idUsuario = #idUsuario);
return (#esCorrecto);
END;
and login
CREATE FUNCTION [dbo].[login](#usuario varchar(20), #password varchar(20))
RETURNS #info TABLE (nombre varchar(70) not null, tipo varchar(30) not null)
AS
BEGIN
DECLARE #idUsuario int = dbo.usuarioExistetest(#usuario);
DECLARE #passCorrecto bit = dbo.passwordCorrectotest(#idUsuario, #password);
INSERT #info
SELECT
usuarios.nombreUsuario, tiposUsuarios.tipoUsuario
FROM
usuarios
LEFT JOIN
tiposUsuarios
ON
usuarios.idTipoUsuario = tiposUsuarios.idTipoUsuario
WHERE
usuarios.idUsuario = #idUsuario and
usuarios.estatus = 'ACTIVO' and
#passCorrecto = 'true';
RETURN
END;
I would like to know if in SQL is it possible to return a varchar value from a stored procedure, most of the examples I have seen the return value is an int.
Example within a procedure:
declare #ErrorMessage varchar(255)
if #TestFlag = 0
set #ErrorMessage = 'Test'
return #ErrorMessage
You can use out parameter or the resulset to return any data type.
Return values should always be integer
CREATE PROCEDURE GetImmediateManager
#employeeID INT,
#managerName VARCHAR OUTPUT
AS
BEGIN
SELECT #managerName = ManagerName
FROM HumanResources.Employee
WHERE EmployeeID = #employeeID
END
Taken from here
You will need to create a stored function for that:
create function dbo.GetLookupValue(#value INT)
returns varchar(100)
as begin
declare #result varchar(100)
select
#result = somefield
from
yourtable
where
ID = #value;
return #result
end
You can then use this stored function like this:
select dbo.GetLookupValue(4)
Marc
A stored procedure's return code is always integer, but you can have OUTPUT parameters that are any desired type -- see http://msdn.microsoft.com/en-us/library/aa174792.aspx .