Sql string manipulation within stored procedure - sql

I have a field which contains article titles. I need to create friendly or pretty url's out of the article titles.
I need help manipulating the string with SQL. This has to be done within a stored procedure or function.
The requirements:
The only characters allowed are lowercase letters and numbers (a-z and 0-9)
All spaces need to be replaced with dashes.
Thanks!
(updated) I am using Sql Server 2008

I found the answer over here. Thank you all!
How to strip all non-alphabetic characters from string in SQL Server?
CREATE Function [dbo].[create_pretty_url](#Temp VarChar(1000))
Returns VarChar(1000)
AS
Begin
While PatIndex('%[^A-za-z0-9]%', #Temp) > 0
Set #Temp = LOWER(Stuff(#Temp, PatIndex('%[^A-za-z0-9]%', #Temp), 1, ''))
Return #Temp
End

To check for lowercase letters, you can use a binary collation like Latin1_General_BIN.
This SQL Server procedure checks if a string contains only spaces, digits or lowercase letters. If so, it returns 1 and replaces spaces with underscores. Else it returns -1.
if OBJECT_ID('TestProc') is null
exec ('create procedure TestProc as select 1')
go
alter procedure TestProc(
#str varchar(256),
#result varchar(256) output)
as
begin
set #result = null
set #str = REPLACE(#str,' ','_')
if #str like '%[^0-9a-z_]%' collate Latin1_General_BIN
return -1
set #result = #str
return 1
end
go
Test data:
declare #rc int
declare #result varchar(256)
exec #rc = TestProc '11 aa', #result out
select #rc, #result
exec #rc = TestProc 'NO CAPS', #result out
select #rc, #result
exec #rc = TestProc '%#$#$', #result out
select #rc, #result
-->
1 11_aa
-1 NULL
-1 NULL

You did not state which database, or version for that matter, but lets go with:
I you were to be using Sql Server 2005, 2008, have a look at using CLR functions
Adding Regular Expressions (Regex) to SQL Server 2005

Related

Using a SQL User Defined Function with an UPDATE

I have a Function that removes any non alpha numerical characters, and a stored procedure that does several updates to the EMIR table. My question is, how do I write an update statement to call the function RemoveNonAlphaNumericCharacters and update the field 'Underlying_Security_Name'
USE EMIR
GO
ALTER FUNCTION [dbo].[RemoveNonAlphaNumericCharacters]
(
-- Add the parameters for the function here
#String NVARCHAR(100)
)
RETURNS nvarchar(100)
AS
BEGIN
DECLARE #Keep_Value AS NVARCHAR(50)
SET #Keep_Value = '%[^a-z0-9 ]%'
WHILE PATINDEX(#Keep_Value, #String) > 0
BEGIN
SET #String = STUFF(#String, PATINDEX(#Keep_Value, #String), 1, '')
END
RETURN #String
END
GO
You could do something like this.
UPDATE EMIR.table_name
SET Underlying_Security_Name = dbo.RemoveNonAlphaNumericCharacters(Underlying_Security_Name​);

Creating multiple UDFs in one batch - SQL Server

I'm asking this question for SQL Server 2008 R2
I'd like to know if there is a way to create multiple functions in a single batch statement.
I've made the following code as an example; suppose I want to take a character string and rearrange its letters in alphabetical order. So, 'Hello' would become 'eHllo'
CREATE FUNCTION char_split (#string varchar(max))
RETURNS #characters TABLE
(
chars varchar(2)
)
AS
BEGIN
DECLARE #length int,
#K int
SET #length = len(#string)
SET #K = 1
WHILE #K < #length+1
BEGIN
INSERT INTO #characters
SELECT SUBSTRING(#string,#K,1)
SET #K = #K+1
END
RETURN
END
CREATE FUNCTION rearrange (#string varchar(max))
RETURNS varchar(max)
AS
BEGIN
DECLARE #SplitData TABLE (
chars varchar(2)
)
INSERT INTO #SplitData SELECT * FROM char_split(#string)
DECLARE #Output varchar(max)
SELECT #Output = coalesce(#Output,' ') + cast(chars as varchar(10))
from #SplitData
order by chars asc
RETURN #Output
END
declare #string varchar(max)
set #string = 'Hello'
select dbo.rearrange(#string)
When I try running this code, I get this error:
'CREATE FUNCTION' must be the first statement in a query batch.
I tried enclosing each function in a BEGIN END block, but no luck. Any advice?
Just use a GO statement between the definition of the UDFs
Not doable. SImple like that.
YOu can make it is one statement using a GO between them.
But as the GO is a batch delimiter.... this means you send multiple batches, which is explicitly NOT Wanted in your question.
So, no - it is not possible to do that in one batch as the error clearly indicates.

declaring T-Sql parameter for comma delimited list of integers

I have a table that contains a list of performances. These performances are grouped by production number. What I am trying to do is create a stored procedure that will return the last performance for each production entered. I would like to be able to input the production ids as a list of ids. Below is my procedure so far. Difficulty is I'm not sure how best to declare the #prod_no parameter to be used in the IN statement.
CREATE PROCEDURE IP_MAX_PERF_DATE
-- Add the parameters for the stored procedure here
#prod_no
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT [prod_season_no], MAX([perf_dt]) As max_dt FROM [T_PERF] WHERE [prod_season_no] IN (#prod)
GROUP By [prod_season_no];
END
GO
Any ideas
Try the sp_executesql
CREATE PROCEDURE IP_MAX_PERF_DATE
#prod_no nvarchar(500)
AS
BEGIN
SET NOCOUNT ON;
declare #statement nvarchar(1000)
set #statement = N'SELECT [prod_season_no], MAX([perf_dt]) As max_dt FROM [T_PERF] WHERE [prod_season_no] IN (' + #prod_no + ') GROUP By [prod_season_no]'
EXEC sp_executesql
#stmt = #statement
END
GO
generally there are three ways to pass in a list of Ids:
Option 1: use comma separated list and split it in the stored procedure. this requires you to have a split function, or use dynamic sql (not preferred most of the time due to performance problem - at least hard to see the execution plan and you lose the point of using stored procedure to optimize your query)
Option 2: use xml, and again, you need to query the xml to find out the Ids
Option 3: use table valued parameter, this requires you to have a user defined table type
a detailed comparison could be found here:
http://www.adathedev.co.uk/2010/02/sql-server-2008-table-valued-parameters.html
This is what I've always done for passing in comma sepearted Integer IDs.
ALTER FUNCTION [dbo].[SplitArray]
(
#List varchar(500)
)
RETURNS
#ArrayValues table
(
ListID int
)
AS
BEGIN
DECLARE #ListID varchar(10), #Pos int
SET #List = LTRIM(RTRIM(#List))+ ','
SET #Pos = CHARINDEX(',', #List, 1)
IF REPLACE(#List, ',', '') <> ''
BEGIN
WHILE #Pos > 0
BEGIN
SET #ListID = LTRIM(RTRIM(LEFT(#List, #Pos - 1)))
IF #ListID <> ''
BEGIN
INSERT INTO #ArrayValues (ListID)
VALUES (CAST(#ListID AS int)) --Use Appropriate conversion
END
SET #List = RIGHT(#List, LEN(#List) - #Pos)
SET #Pos = CHARINDEX(',', #List, 1)
END
END
RETURN
END
To use it, simply join it on your query like so:
Select a.* From Apples a Inner Join dbo.SplitArray(#IDList) array on a.AppleID = array.ListID

TSQL using a wildcard in a where clause with dynamic sql

It appears that using the LIKE in a condition with wildcards and a variable inside of dynamic sql doesn't work, although it doesn't give an error. Here's an example.
The column called code has values like A0B01C02,A0B02C2D05,A0B02C2D05, etc and I am trying to match on rows containing a subset like 'B1'. When I do this it works and returns results as expected.
set #sql='select * from table where code like ''%B01%'''
exec sp_executesql #sql
If I hardcode the value of the variable
set #code='B01'
and modify the sql statement to concatenate the quotes and wildcards:
set #sql='select * from table where code like ' +''''+ '%'+#code + '%' + ''''
exec sp_executesql #sql
This returns the results as expected, but I had to hard code the variable. However, when I need to make the match using a variable for B01 and that the variable is set with a select statement, I don't get any results returned. I define an nvarchar like this:
set #code=(select top 1 code from anotherTable where USERID=#PersonId)
I confirmed that the select statement above returns the expected code, however. There is no error, but the query is "executed successfully". Am I missing something in the syntax for the where clause?
You can find a discussion of this at http://ask.sqlservercentral.com/questions/275/dynamic-where-clause-how-can-i-use-a-variable-in-an-in-predicate/312#312
My answer was to do the Parse By Comma Function.
/*****************************************************************
**** Parse A Comma Delimited String Into A Table
*****************************************************************/
ALTER FUNCTION [dbo].[ParseByComma] (
#String VARCHAR(600) )
RETURNS #TblSubString TABLE
(
VarSubString VARCHAR(50)
)
AS
BEGIN
DECLARE #intPos INT,
#SubStr VARCHAR(50)
-- Remove All Spaces
SET #String = REPLACE(#String, ' ','')
-- Find The First Comma
SET #IntPos = CHARINDEX(',', #String)
-- Loop Until There Is Nothing Left Of #String
WHILE #IntPos > 0
BEGIN
-- Extract The String
SET #SubStr = SUBSTRING(#String, 0, #IntPos)
-- Insert The String Into The Table
INSERT INTO #TblSubString (VarSubString) VALUES (#SubStr)
-- Remove The String & Comma Separator From The Original
SET #String = SUBSTRING(#String, LEN(#SubStr) + 2, LEN(#String) - LEN(#SubStr) + 1)
-- Get The New Index To The String
SET #IntPos = CHARINDEX(',', #String)
END
-- Return The Last One
INSERT INTO #TblSubString (VarSubString) VALUES (#String)
RETURN
END
I do not have a SQL Server in front of me at the moment but I wonder if this syntax might work for you?
set #sql='SELECT * FROM table WHERE UPPER(code) LIKE ''%''||(UPPER(COALESCE('''||#code||''',code)))||''%'' '
exec sp_executesql #sql
Best regards,
Kevin

T-SQL: Concept similar to C# params

Does T-SQL allow a variable number of arguments to a stored procedure like params in C#?
EDIT: I'm using SQL Server 2005. That 2008 answer makes me wish we were using it...
In SQL 2008 there's Table-Valued Parameters (TVPs)
Your stored proc can accept lists of parameters..
Finally we're able to do a IN clause without relying on XML!
Mike
No, not for things like UDFs or stored procedures. That's what tables are for. Put the values in a table somewhere (with a common key) and pass the correct key to your procedure.
Typically
CREATE PROCEDURE dbo.sptest
( #xml TEXT )
AS
BEGIN
DECLARE #flag1 INT
DECLARE #flag2 VARCHAR(50)
DECLARE #flag3 DATETIME
DECLARE #idoc INT
exec sp_xml_preparedocument #idoc OUTPUT, #xml
SELECT #flag1 = firstparam, flag2 = secondparam, flag3 = thirdparam
FROM OPENXML(#idoc, '/root', 2) WITH
( firstparam INT, secondparam VARCHAR(50), thirdparam DATETIME) as x
END
exec sptest '<root><firstparam>5</firstparam><secondparam>Joes Bar</secondparam><thirdparam>12/30/2010</thirdparam></root>'
Extend as necessary
Another approach I've seen to passing in params or arrays is to pass in an XML string, dump that to a temporary table/table variable and work with it from that point. Not the easiest when you want to manually run a stored procedure, but it works as a work around to the lack of array/dynamic param support.
I've used a little function to separate a CSV string into a table
That way I could go
SELECT col1, col2
FROM myTable
WHERE myTable.ID IN (SELECT ID FROM dbo.SplitIDs('1,2,3,4,5...'))
My function is below:
CREATE FUNCTION [dbo].[SplitIDs]
(
#IDList varchar(500)
)
RETURNS
#ParsedList table
(
ID int
)
AS
BEGIN
DECLARE #ID varchar(10), #Pos int
SET #IDList = LTRIM(RTRIM(#IDList))+ ','
SET #Pos = CHARINDEX(',', #IDList, 1)
IF REPLACE(#IDList, ',', '') <> ''
BEGIN
WHILE #Pos > 0
BEGIN
SET #ID = LTRIM(RTRIM(LEFT(#IDList, #Pos - 1)))
IF #ID <> ''
BEGIN
INSERT INTO #ParsedList (ID)
VALUES (CAST(#ID AS int)) --Use Appropriate conversion
END
SET #IDList = RIGHT(#IDList, LEN(#IDList) - #Pos)
SET #Pos = CHARINDEX(',', #IDList, 1)
END
END
RETURN
END
I'm sure there are better ways to implement this, this is one way I found online and it works well for what I'm doing. If there are some improvement that can be made please comment.