SQL Server : return string procedure INITCAP - sql

This is what I've done.
create proc INITCAP(#string varchar(30))
as
begin
SET #string = UPPER(LEFT(#string,1)) + LOWER(RIGHT(#string, LEN(#string) -1))
end
declare #lastname varchar
set #lastname = exec INITCAP 'MILLER'
declare #firstname varchar
set #firstname = exec INITCAP 'StEvE'
UPDATE Employee SET firstname = #firstname, lastname = #lastname WHERE empID = 7934
I keep getting the errors:
Msg 156, Level 15, State 1, Procedure INITCAP, Line 97
Incorrect syntax near the keyword 'exec'.
Msg 156, Level 15, State 1, Procedure INITCAP, Line 100
Incorrect syntax near the keyword 'exec'.
What shall I do? I want the procedure INITCAP to work as it does in Oracle: to return a name like: "Steve", "Miller"

Solution #1 (I wouln't use this solution)
You could use OUTPUT parameters thus:
create proc INITCAP(#string varchar(30) OUTPUT)
as
begin
SET #string = UPPER(LEFT(#string,1)) + LOWER(SUBSTRING(#string, 2, 8000))
end
go
declare #lastname varchar
set #lastname = 'MILLER'
exec INITCAP #lastname OUTPUT
declare #firstname varchar
set #firstname = 'StEvE'
exec INITCAP #firstname OUTPUT
Solution #2: Instead, I would choose to create an inline function thus:
CREATE FUNCTION dbo.Capitalize1(#string varchar(30))
RETURNS TABLE
AS
RETURN
SELECT UPPER(LEFT(#string,1)) + LOWER(SUBSTRING(#string, 2, 8000)) AS Result;
Usage:
UPDATE e
SET firstname = cap.Result
FROM Employee e
CROSS APPLY dbo.Capitalize1(e.firstname) cap;
Solution #3: Another option could be a scalar function with schemabinding option (for performance reasons):
CREATE FUNCTION dbo.Capitalize2(#string varchar(30))
RETURNS VARCHAR(30)
WITH SCHEMABINDING
AS
BEGIN
RETURN UPPER(LEFT(#string,1)) + LOWER(SUBSTRING(#string, 2, 8000));
END;
Usage:
UPDATE Employee
SET firstname = dbo.Capitalize2(firstname);

Do you really need a stored Proc for this ??? I would do something like this a UDF would do the job just fine i think....
CREATE FUNCTION dbo.udf_SomeFunction (#String VARCHAR(30))
RETURNS VARCHAR(30)
AS
BEGIN
DECLARE #rtnString VARCHAR(30);
SET #rtnString = UPPER(LEFT(#string,1)) + LOWER(RIGHT(#string, LEN(#string) -1))
RETURN(#rtnString);
END;
You can call this function in your SELECT statement , Having a proc doing the same job doesnt give you this flexibility
UPDATE
UPDATE Employee
SET firstname = dbo.udf_SomeFunction (firstname)
, lastname = dbo.udf_SomeFunction (lastname)
WHERE empID = 7934

You should use a function to achieve what you need and use a syntax that you want in setting the variables. Please not that you have to put GO between function creation and the rest.
create function INITCAP(#string varchar(30))
returns varchar(30)
as
begin
return UPPER(LEFT(#string,1)) + LOWER(RIGHT(#string, LEN(#string) -1))
end
go
declare #lastname varchar
set #lastname = dbo.INITCAP('MILLER')
declare #firstname varchar
set #firstname = dbo.INITCAP('StEvE')
UPDATE Employee SET firstname = #firstname, lastname = #lastname WHERE empID = 7934

Related

SQL Server 2005: column cannot be persisted because is non-deterministic [duplicate]

I have the following user-defined function:
create function [dbo].[FullNameLastFirst]
(
#IsPerson bit,
#LastName nvarchar(100),
#FirstName nvarchar(100)
)
returns nvarchar(201)
as
begin
declare #Result nvarchar(201)
set #Result = (case when #IsPerson = 0 then #LastName else case when #FirstName = '' then #LastName else (#LastName + ' ' + #FirstName) end end)
return #Result
end
I can't create an Index on a computed column using this function cause it's not deterministic.
Someone could explain why is it not deterministic and eventually how to modify to make it deterministic?
Thanks
You just need to create it with schemabinding.
SQL Server will then verify whether or not it meets the criteria to be considered as deterministic (which it does as it doesn't access any external tables or use non deterministic functions such as getdate()).
You can verify that it worked with
SELECT OBJECTPROPERTY(OBJECT_ID('[dbo].[FullNameLastFirst]'), 'IsDeterministic')
Adding the schemabinding option to your original code works fine but a slightly simpler version would be.
CREATE FUNCTION [dbo].[FullNameLastFirst] (#IsPerson BIT,
#LastName NVARCHAR(100),
#FirstName NVARCHAR(100))
RETURNS NVARCHAR(201)
WITH SCHEMABINDING
AS
BEGIN
RETURN CASE
WHEN #IsPerson = 0
OR #FirstName = '' THEN #LastName
ELSE #LastName + ' ' + #FirstName
END
END
You need to declare the User Defined Function WITH SCHEMABINDING to appease the 'deterministic' requirement of an index on the computed column.
A function declared WITH SCHEMABINDING will retain additional knowledge about the object dependencies used in the function (e.g. columns in the table), and will prevent any changes to these columns, unless the function itself is dropped beforehand.
Deterministic functions can also assist Sql Server in optimizing its execution plans, most notably the Halloween Protection problem.
Here's an example of creating an index on a computed column using a schema bound function:
create function [dbo].[FullNameLastFirst]
(
#IsPerson bit,
#LastName nvarchar(100),
#FirstName nvarchar(100)
)
returns nvarchar(201)
with schemabinding
as
begin
declare #Result nvarchar(201)
set #Result = (case when #IsPerson = 0 then #LastName
else case when #FirstName = '' then #LastName
else (#LastName + ' ' + #FirstName) end end)
return #Result
end
create table Person
(
isperson bit,
lastname nvarchar(100),
firstname nvarchar(100),
fullname as [dbo].[FullNameLastFirst] (isperson, lastname, firstname)
)
go
insert into person(isperson, lastname, firstname) values (1,'Firstname', 'Surname')
go
create index ix1_person on person(fullname)
go
select fullname from Person with (index=ix1_person) where fullname = 'Firstname Surname'
go

How to make a Non-Deterministic function deterministic? [duplicate]

I have the following user-defined function:
create function [dbo].[FullNameLastFirst]
(
#IsPerson bit,
#LastName nvarchar(100),
#FirstName nvarchar(100)
)
returns nvarchar(201)
as
begin
declare #Result nvarchar(201)
set #Result = (case when #IsPerson = 0 then #LastName else case when #FirstName = '' then #LastName else (#LastName + ' ' + #FirstName) end end)
return #Result
end
I can't create an Index on a computed column using this function cause it's not deterministic.
Someone could explain why is it not deterministic and eventually how to modify to make it deterministic?
Thanks
You just need to create it with schemabinding.
SQL Server will then verify whether or not it meets the criteria to be considered as deterministic (which it does as it doesn't access any external tables or use non deterministic functions such as getdate()).
You can verify that it worked with
SELECT OBJECTPROPERTY(OBJECT_ID('[dbo].[FullNameLastFirst]'), 'IsDeterministic')
Adding the schemabinding option to your original code works fine but a slightly simpler version would be.
CREATE FUNCTION [dbo].[FullNameLastFirst] (#IsPerson BIT,
#LastName NVARCHAR(100),
#FirstName NVARCHAR(100))
RETURNS NVARCHAR(201)
WITH SCHEMABINDING
AS
BEGIN
RETURN CASE
WHEN #IsPerson = 0
OR #FirstName = '' THEN #LastName
ELSE #LastName + ' ' + #FirstName
END
END
You need to declare the User Defined Function WITH SCHEMABINDING to appease the 'deterministic' requirement of an index on the computed column.
A function declared WITH SCHEMABINDING will retain additional knowledge about the object dependencies used in the function (e.g. columns in the table), and will prevent any changes to these columns, unless the function itself is dropped beforehand.
Deterministic functions can also assist Sql Server in optimizing its execution plans, most notably the Halloween Protection problem.
Here's an example of creating an index on a computed column using a schema bound function:
create function [dbo].[FullNameLastFirst]
(
#IsPerson bit,
#LastName nvarchar(100),
#FirstName nvarchar(100)
)
returns nvarchar(201)
with schemabinding
as
begin
declare #Result nvarchar(201)
set #Result = (case when #IsPerson = 0 then #LastName
else case when #FirstName = '' then #LastName
else (#LastName + ' ' + #FirstName) end end)
return #Result
end
create table Person
(
isperson bit,
lastname nvarchar(100),
firstname nvarchar(100),
fullname as [dbo].[FullNameLastFirst] (isperson, lastname, firstname)
)
go
insert into person(isperson, lastname, firstname) values (1,'Firstname', 'Surname')
go
create index ix1_person on person(fullname)
go
select fullname from Person with (index=ix1_person) where fullname = 'Firstname Surname'
go

Getting Error On Stored Procedure while getting employee names from table

I have this SQL Server stored procedure:
use PracticeDatabase
Go
alter procedure spGetEmpByGender
#gender nvarchar(50),
#name nvarchar(50) output
as
begin
select #name = Emp_Name
from tblPracticeEmpTable
where gender = #gender
End
declare #EmpNames nvarchar(50)
exec spGetEmpByGender 'male', #EmpNames output
select #EmpNames
While executing the above procedure, I get this error:
Msg 217, Level 16, State 1, Procedure spGetEmpByGender, Line 10
Maximum stored procedure, function, trigger, or view nesting level
exceeded (limit 32).
Execute the following and see what happens
use PracticeDatabase
Go
IF OBJECT_ID('spGetEmpByGender') IS NOT NULL
DROP PROCEDURE spGetEmpByGender
GO
CREATE procedure spGetEmpByGender
#gender nvarchar(50),
#name nvarchar(50) output
as
begin
select Top 1 #name = Emp_Name
from tblPracticeEmpTable
where gender = #gender
End
GO
declare #EmpNames nvarchar(50)
exec spGetEmpByGender 'male', #EmpNames output
select #EmpNames
GO

Sql Server deterministic user-defined function

I have the following user-defined function:
create function [dbo].[FullNameLastFirst]
(
#IsPerson bit,
#LastName nvarchar(100),
#FirstName nvarchar(100)
)
returns nvarchar(201)
as
begin
declare #Result nvarchar(201)
set #Result = (case when #IsPerson = 0 then #LastName else case when #FirstName = '' then #LastName else (#LastName + ' ' + #FirstName) end end)
return #Result
end
I can't create an Index on a computed column using this function cause it's not deterministic.
Someone could explain why is it not deterministic and eventually how to modify to make it deterministic?
Thanks
You just need to create it with schemabinding.
SQL Server will then verify whether or not it meets the criteria to be considered as deterministic (which it does as it doesn't access any external tables or use non deterministic functions such as getdate()).
You can verify that it worked with
SELECT OBJECTPROPERTY(OBJECT_ID('[dbo].[FullNameLastFirst]'), 'IsDeterministic')
Adding the schemabinding option to your original code works fine but a slightly simpler version would be.
CREATE FUNCTION [dbo].[FullNameLastFirst] (#IsPerson BIT,
#LastName NVARCHAR(100),
#FirstName NVARCHAR(100))
RETURNS NVARCHAR(201)
WITH SCHEMABINDING
AS
BEGIN
RETURN CASE
WHEN #IsPerson = 0
OR #FirstName = '' THEN #LastName
ELSE #LastName + ' ' + #FirstName
END
END
You need to declare the User Defined Function WITH SCHEMABINDING to appease the 'deterministic' requirement of an index on the computed column.
A function declared WITH SCHEMABINDING will retain additional knowledge about the object dependencies used in the function (e.g. columns in the table), and will prevent any changes to these columns, unless the function itself is dropped beforehand.
Deterministic functions can also assist Sql Server in optimizing its execution plans, most notably the Halloween Protection problem.
Here's an example of creating an index on a computed column using a schema bound function:
create function [dbo].[FullNameLastFirst]
(
#IsPerson bit,
#LastName nvarchar(100),
#FirstName nvarchar(100)
)
returns nvarchar(201)
with schemabinding
as
begin
declare #Result nvarchar(201)
set #Result = (case when #IsPerson = 0 then #LastName
else case when #FirstName = '' then #LastName
else (#LastName + ' ' + #FirstName) end end)
return #Result
end
create table Person
(
isperson bit,
lastname nvarchar(100),
firstname nvarchar(100),
fullname as [dbo].[FullNameLastFirst] (isperson, lastname, firstname)
)
go
insert into person(isperson, lastname, firstname) values (1,'Firstname', 'Surname')
go
create index ix1_person on person(fullname)
go
select fullname from Person with (index=ix1_person) where fullname = 'Firstname Surname'
go

SQL Server: Return uniqueidentifier from stored procedure

Can I return UNIQUEIDENTIFIER from a stored procedure using the RETURN statement or is it only by using the OUTPUT statement?
i.e to return the PersonID UNIQUEIDENTIFIER:
CREATE PROCEDURE CreatePerson
#Name NVARCHAR(255),
#Desc TEXT
AS
DECLARE #Count INT
DECLARE #JobFileGUID UNIQUEIDENTIFIER
-- Check if job exists?
SET #Count = (SELECT COUNT(Name) AS Name FROM Person WHERE Name=#Name)
IF #Count < 1
BEGIN
SET #PersonGUID = NEWID();
INSERT INTO Person
(PersonID, Name, [Desc])
VALUES (#PersonGUID, #Name, #Desc)
END
SELECT #PersonGUID = Person.PersonID
FROM Person
WHERE Name = #Name
RETURN #PersonGUID
GO
Thanks
In stored procedure - only using the OUTPUT statement. In function - return.
Use:
CREATE PROCEDURE CreatePerson
#Name NVARCHAR(255),
#Desc TEXT,
#PersonGUID UNIQUEIDENTIFIER OUTPUT
AS
BEGIN
SET #PersonGUID = ...
END
How to call:
DECLARE
#name NVARCHAR(255),
#desc TEXT,
#personGUID UNIQUEIDENTIFIER
SET #name = 'Bob'
SET #desc = 'One handsome man.'
EXEC [Database].[schema].CreatePerson #name, #desc, #personGUID OUTPUT
From the documentation you can actually see that a return in a stored procedure is actually used as a response code, hence you get the exception when trying to return a uniqueidentifier.
https://learn.microsoft.com/en-us/sql/relational-databases/stored-procedures/return-data-from-a-stored-procedure?view=sql-server-ver16#return-data-using-a-return-code
How I solved it, is by just performing a SELECT after the insert of the generated unique identifier.
DECLARE #ReportId UNIQUEIDENTIFIER;
SET #ReportId = NEWID();
INSERT INTO [dbo].[Report]
([ReportId]
,[ReportName])
VALUES
(#ReportId
,#ReportName)
SELECT #ReportId as ReportIdInternal
You'll have to see how to perform that with multiple selects though.
CREATE TABLE [dbo].[tbl_Clients]( [ClientID] [uniqueidentifier] NULL, [ClientName] varchar NULL, [ClientEnabled] [bit] NULL ) ON [PRIMARY]
GO
CREATE PROCEDURE [dbo].[sp_ClientCreate] #in_ClientName varchar(250) = "New Client 123", #in_ClientEnabled bit, #out_ClientId uniqueidentifier OUTPUT AS
SET #out_ClientId = NEWID();
INSERT INTO tbl_Clients(ClientId, ClientName, ClientEnabled) VALUES( #out_ClientId, #in_ClientName, #in_ClientEnabled)
DECLARE #return_value int, #out_ClientId uniqueidentifier
EXEC #return_value = [dbo].[sp_ClientCreate] #in_ClientName = N'111', #in_ClientEnabled = 1, #out_ClientId = #out_ClientId OUTPUT
SELECT #out_ClientId as N'#out_ClientId'
SELECT 'Return Value' = #return_value
GO
Result:-59A6D7FE-8C9A-4ED3-8FC6-31A989CCC8DB