I need to create a function that I found here: http://vyaskn.tripod.com/code/propercase.txt It converts text to "ProperCase," first letter of every word to uppercase.
CREATE FUNCTION PROPERCASE
(
-- The string to be converted to proper case
#input VARCHAR( 8000 )
)
-- This function returns the proper case string of varchar type
RETURNS VARCHAR( 8000 )
AS
BEGIN
IF #input IS NULL
BEGIN
-- Just return NULL if input string is NULL
RETURN NULL
END
-- Character variable declarations
DECLARE #output VARCHAR( 8000 )
-- Integer variable declarations
DECLARE #ctr INT, #len INT, #found_at INT
-- Constant declarations
DECLARE #LOWER_CASE_a INT, #LOWER_CASE_z INT, #Delimiter CHAR(3), #UPPER_CASE_A INT, #UPPER_CASE_Z INT
-- Variable/Constant initializations
SET #ctr = 1
SET #len = LEN(#input)
SET #output = ''
SET #LOWER_CASE_a = 97
SET #LOWER_CASE_z = 122
SET #Delimiter = ' ,-'
SET #UPPER_CASE_A = 65
SET #UPPER_CASE_Z = 90
WHILE #ctr <= #len
BEGIN
-- This loop will take care of reccuring white spaces
WHILE CHARINDEX(SUBSTRING(#input,#ctr,1), #Delimiter) > 0
BEGIN
SET #output = #output + SUBSTRING(#input,#ctr,1)
SET #ctr = #ctr + 1
END
IF ASCII(SUBSTRING(#input,#ctr,1)) BETWEEN #LOWER_CASE_a AND #LOWER_CASE_z
BEGIN
-- Converting the first character to upper case
SET #output = #output + UPPER(SUBSTRING(#input,#ctr,1))
END
ELSE
BEGIN
SET #output = #output + SUBSTRING(#input,#ctr,1)
END
SET #ctr = #ctr + 1
WHILE CHARINDEX(SUBSTRING(#input,#ctr,1), #Delimiter) = 0 AND (#ctr <= #len)
BEGIN
IF ASCII(SUBSTRING(#input,#ctr,1)) BETWEEN #UPPER_CASE_A AND #UPPER_CASE_Z
BEGIN
SET #output = #output + LOWER(SUBSTRING(#input,#ctr,1))
END
ELSE
BEGIN
SET #output = #output + SUBSTRING(#input,#ctr,1)
END
SET #ctr = #ctr + 1
END
END
RETURN #output
END
I need a function to do that, but it's giving me error...
You are using MySQL, but the syntax you have is for SQL Server. Please read the documentation about MySQL's syntax and convert your procedure to use that syntax. The major constructs are the same, but the syntax is a little different. Here are some things to start with:
Local variables never start with #.
IF is condition followed by THEN followed by any number of lines of code, followed by END IF. The BEGIN...END construct is not used for IF statements in MySQL.
The functions are different. You won't use CHARINDEX but instead INSTR.
Here's the relevant MySQL documentation: http://dev.mysql.com/doc/refman/5.5/en/stored-routines-syntax.html and http://dev.mysql.com/doc/refman/5.5/en/sql-syntax-compound-statements.html.
Related
I need the following output in SQL server 2008
problem is to remove numbers from string
i.e column name is associated_id which is nvarchar type and value could be (23,34,45)
But I want the following result (23,45).
May this help
CREATE FUNCTION [dbo].[GetAlphabetFromAlphaNumeric]
(#strAlphaNumeric VARCHAR(500))
RETURNS VARCHAR(500)
AS
BEGIN
DECLARE #intAlpha INT
SET #intAlpha = PATINDEX('%[0-9]%', #strAlphaNumeric)
BEGIN
WHILE #intAlpha > 0
BEGIN
SET #strAlphaNumeric = STUFF(#strAlphaNumeric, #intAlpha, 1, '' )
SET #intAlpha = PATINDEX('%[0-9]%', #strAlphaNumeric )
END
END
RETURN ISNULL(#strAlphaNumeric,0)
END
I have a long string.I want to check throughout this string for consecutive 15 letters if there is no space i have to manually put a space in sql server. Can any one pls help??
For eg. my string is 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ'
then it should appear like 'ABCDEFGHIJKLMNOP QRSTUVWXYZABCDE FGHIJKLMNOPQRST UVWXYZ'
#dcp1986: I tried with your function as below.
SELECT dbo.UF_StringSplitter('HeloEveryonehru Howslyfgoingonn HaveaGoodDayGoodMorning')
But an unexpected split occured. I think your function must be modified as below for the correct result:
IF EXISTS(SELECT * FROM sysobjects WHERE ID = OBJECT_ID('UF_StringSplitter'))
DROP FUNCTION UF_StringSplitter
GO
CREATE FUNCTION UF_StringSplitter (
#psCSString VARCHAR(MAX)
)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #sTemp VARCHAR(MAX)
DECLARE #tTemp VARCHAR(MAX)
SET #tTemp=''
WHILE LEN(#psCSString)>15
BEGIN
SET #sTemp = LEFT(LTRIM(#psCSString), 15)
SET #psCSString = LTRIM(SUBSTRING(#psCSString,16, LEN(#psCSString)))
IF #psCSString LIKE ' %'
SET #tTemp=#tTemp+#sTemp
ELSE
SET #tTemp=#tTemp+#sTemp+' '
END
SET #tTemp=#tTemp+#psCSString
RETURN #tTemp
END
You could use a function like this
IF EXISTS(SELECT * FROM sysobjects WHERE ID = OBJECT_ID('UF_StringSplitter'))
DROP FUNCTION UF_StringSplitter
GO
CREATE FUNCTION UF_StringSplitter
(
#psCSString VARCHAR(MAX)
)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #sTemp VARCHAR(MAX)
DECLARE #tTemp VARCHAR(MAX)
SET #tTemp=''
WHILE LEN(#psCSString)>15
BEGIN
SET #sTemp = LEFT(#psCSString, 15)
SET #psCSString = SUBSTRING(#psCSString,16, LEN(#psCSString))
IF #psCSString LIKE ' %'
SET #tTemp=#tTemp+#sTemp
ELSE
SET #tTemp=#tTemp+#sTemp+' '
END
SET #tTemp=#tTemp+#psCSString
RETURN #tTemp
END
Go
Here i have hard coded the splitting value, and you can use the function
UPDATE mytable SET mycol=dbo.UF_StringSplitter(mycol)
I don't know how to do it on a single statement, but you can create a sql function something like this
create function AddStuffCharacterInLength (#original nvarchar(100), #take int, #stuff varchar(100))
returns nvarchar(200)
AS
BEGIN
declare #result nvarchar(200)
declare #len int
declare #skip int
set #len = len(#original)
set #result = ''
set #skip = (#take * -1) + 1
while #len > 0
begin
set #result = #result + substring(#original, #skip + #take, #take)
set #len = #len - #take
set #skip = #skip + #take
if #len > 0
set #result = #result + ' '
end
RETURN #result
END
And use it like this
select dbo.AddStuffCharacterInLength ('ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ',15, ' ')
And the output should be
----------------------------------------------------------------------------------------------------
ABCDEFGHIJKLMNO PQRSTUVWXYZABCD EFGHIJKLMNOPQRS TUVWXYZ
(1 row(s) affected)
I have the following table with each row having comma-separated values:
ID
-----------------------------------------------------------------------------
10031,10042
10064,10023,10060,10065,10003,10011,10009,10012,10027,10004,10037,10039
10009
20011,10027,10032,10063,10023,10033,20060,10012,10020,10031,10011,20036,10041
I need to get a count for each ID (a groupby).
I am just trying to avoid cursor implementation and stumped on how to do this without cursors.
Any Help would be appreciated !
You will want to use a split function:
create FUNCTION [dbo].[Split](#String varchar(MAX), #Delimiter char(1))
returns #temptable TABLE (items varchar(MAX))
as
begin
declare #idx int
declare #slice varchar(8000)
select #idx = 1
if len(#String)<1 or #String is null return
while #idx!= 0
begin
set #idx = charindex(#Delimiter,#String)
if #idx!=0
set #slice = left(#String,#idx - 1)
else
set #slice = #String
if(len(#slice)>0)
insert into #temptable(Items) values(#slice)
set #String = right(#String,len(#String) - #idx)
if len(#String) = 0 break
end
return
end;
And then you can query the data in the following manner:
select items, count(items)
from table1 t1
cross apply dbo.split(t1.id, ',')
group by items
See SQL Fiddle With Demo
Well, the solution i always use, and probably there might be a better way, is to use a function that will split everything. No use for cursors, just a while loop.
if OBJECT_ID('splitValueByDelimiter') is not null
begin
drop function splitValueByDelimiter
end
go
create function splitValueByDelimiter (
#inputValue varchar(max)
, #delimiter varchar(1)
)
returns #results table (value varchar(max))
as
begin
declare #delimeterIndex int
, #tempValue varchar(max)
set #delimeterIndex = 1
while #delimeterIndex > 0 and len(isnull(#inputValue, '')) > 0
begin
set #delimeterIndex = charindex(#delimiter, #inputValue)
if #delimeterIndex > 0
set #tempValue = left(#inputValue, #delimeterIndex - 1)
else
set #tempValue = #inputValue
if(len(#tempValue)>0)
begin
insert
into #results
select #tempValue
end
set #inputValue = right(#inputValue, len(#inputValue) - #delimeterIndex)
end
return
end
After that you can call the output like this :
if object_id('test') is not null
begin
drop table test
end
go
create table test (
Id varchar(max)
)
insert
into test
select '10031,10042'
union all select '10064,10023,10060,10065,10003,10011,10009,10012,10027,10004,10037,10039'
union all select '10009'
union all select '20011,10027,10032,10063,10023,10033,20060,10012,10020,10031,10011,20036,10041'
select value
from test
cross apply splitValueByDelimiter(Id, ',')
Hope it helps, although i am still looping through everything
After reiterating the comment above about NOT putting multiple values into a single column (Use a separate child table with one value per row!),
Nevertheless, one possible approach: use a UDF to convert delimited string to a table. Once all the values have been converted to tables, combine all the tables into one table and do a group By on that table.
Create Function dbo.ParseTextString (#S Text, #delim VarChar(5))
Returns #tOut Table
(ValNum Integer Identity Primary Key,
sVal VarChar(8000))
As
Begin
Declare #dlLen TinyInt -- Length of delimiter
Declare #wind VarChar(8000) -- Will Contain Window into text string
Declare #winLen Integer -- Length of Window
Declare #isLastWin TinyInt -- Boolean to indicate processing Last Window
Declare #wPos Integer -- Start Position of Window within Text String
Declare #roVal VarChar(8000)-- String Data to insert into output Table
Declare #BtchSiz Integer -- Maximum Size of Window
Set #BtchSiz = 7900 -- (Reset to smaller values to test routine)
Declare #dlPos Integer -- Position within Window of next Delimiter
Declare #Strt Integer -- Start Position of each data value within Window
-- -------------------------------------------------------------------------
-- ---------------------------
If #delim is Null Set #delim = '|'
If DataLength(#S) = 0 Or
Substring(#S, 1, #BtchSiz) = #delim Return
-- --------------------------------------------
Select #dlLen = DataLength(#delim),
#Strt = 1, #wPos = 1,
#wind = Substring(#S, 1, #BtchSiz)
Select #winLen = DataLength(#wind),
#isLastWin = Case When DataLength(#wind) = #BtchSiz
Then 0 Else 1 End,
#dlPos = CharIndex(#delim, #wind, #Strt)
-- --------------------------------------------
While #Strt <= #winLen
Begin
If #dlPos = 0 Begin -- No More delimiters in window
If #isLastWin = 1 Set #dlPos = #winLen + 1
Else Begin
Set #wPos = #wPos + #Strt - 1
Set #wind = Substring(#S, #wPos, #BtchSiz)
-- ----------------------------------------
Select #winLen = DataLength(#wind), #Strt = 1,
#isLastWin = Case When DataLength(#wind) = #BtchSiz
Then 0 Else 1 End,
#dlPos = CharIndex(#delim, #wind, 1)
If #dlPos = 0 Set #dlPos = #winLen + 1
End
End
-- -------------------------------
Insert #tOut (sVal)
Select LTrim(Substring(#wind,
#Strt, #dlPos - #Strt))
-- -------------------------------
-- Move #Strt to char after last delimiter
Set #Strt = #dlPos + #dlLen
Set #dlPos = CharIndex(#delim, #wind, #Strt)
End
Return
End
Then write, (using your table schema),
Declare #AllVals VarChar(8000)
Select #AllVals = Coalesce(#allVals + ',', '') + ID
From Table Where ID Is Not null
-- -----------------------------------------
Select sVal, Count(*)
From dbo.ParseTextString(#AllVals, ',')
Group By sval
I was wondering, if there is some way to shuffle the letters of a string in mysql/sql, i.e. something like the pseudocode: SELECT SHUFFLE('abcdef')?
Couldn't find any from http://dev.mysql.com/doc/refman/5.0/en/string-functions.html and searching for it just seems to find solutions for shuffling results, not a string.
Here you go:
DELIMITER //
DROP FUNCTION IF EXISTS shuffle //
CREATE FUNCTION shuffle(
v_chars TEXT
)
RETURNS TEXT
NOT DETERMINISTIC -- multiple RAND()'s
NO SQL
SQL SECURITY INVOKER
COMMENT ''
BEGIN
DECLARE v_retval TEXT DEFAULT '';
DECLARE u_pos INT UNSIGNED;
DECLARE u INT UNSIGNED;
SET u = LENGTH(v_chars);
WHILE u > 0
DO
SET u_pos = 1 + FLOOR(RAND() * u);
SET v_retval = CONCAT(v_retval, MID(v_chars, u_pos, 1));
SET v_chars = CONCAT(LEFT(v_chars, u_pos - 1), MID(v_chars, u_pos + 1, u));
SET u = u - 1;
END WHILE;
RETURN v_retval;
END;
//
DELIMITER ;
SELECT shuffle('abcdef');
See sqlfiddle.com for the output.
Tested successfully with mariadb 10.1 (mysql 5.6 equivalent)
Edit: this solution is for Microsoft SQL Server.
As it's not allowed to use RAND() in user defined function, we create a view to use it later in our shuffle function:
CREATE VIEW randomView
AS
SELECT RAND() randomResult
GO
The actual shuffle function is as following:
CREATE FUNCTION shuffle(#string NVARCHAR(MAX))
RETURNS NVARCHAR(MAX) AS
BEGIN
DECLARE #pos INT
DECLARE #char CHAR(1)
DECLARE #shuffeld NVARCHAR(MAX)
DECLARE #random DECIMAL(18,18)
WHILE LEN(#string) > 0
BEGIN
SELECT #random = randomResult FROM randomView
SET #pos = (CONVERT(INT, #random*1000000) % LEN(#string)) + 1
SET #char = SUBSTRING(#string, #pos, 1)
SET #shuffeld = CONCAT(#shuffeld, #char)
SET #string = CONCAT(SUBSTRING(#string, 1, #pos-1), SUBSTRING(#string, #pos+1, LEN(#string)))
END
RETURN #shuffeld
END
Calling the function
DECLARE #string NVARCHAR(MAX) = 'abcdefghijklmnonpqrstuvwxyz0123456789!"ยง$%&/()='
SELECT dbo.shuffle(#string)
There is nothing in standard SQL - your best bet is probably to write a user defined function
I'm working on a project involving C# and a SQL Server 2008 database.
In one of the tables, I have a field (nvarchar(15)) which will contain an IP address.
I'd like to add a check constraint which will validate that the input value is actually an IP address.
I wanted to use a regex to do that, but it seems that this feature is not supported by default. I saw things about writing a customm dll with UDF inside (MSDN tutorial), but I don't really understand how it works (i.e. where should I place the dll ?)
Is there a "simple" way to add such a constraint ?
Any solution is welcome.
Thanks in advance !
There are several way of doing this - the most performant one would probably be a CLR function in the database.
This is because SQL has fairly poor text manipulation tooling and no native RegEx in SQL Server.
As other have said, this is better handled by an application before insertion to the DB.
It shouldn't be handled in the database, it should be handled first and foremost in the application.
There's no harm in then adding a check to the database, but leaving it up to the DB to filter input is very sketchy.
The easiest way I can think of is to create a function like fnCheckIP and use this function in the constraint.
There's no need to use UDF.
create function fnCheckIP(#ip varchar(15)) returns bit
AS
begin
if (#ip is null)
return null
declare #num1 int
declare #num varchar(15)
declare #pos int
while (#ip is not null)
begin
set #pos = IsNull(NullIf(charindex('.', #ip), 0), Len(#ip) + 1)
set #num = substring(#ip, 1, #pos - 1)
if (isnumeric(#num) = 0) or (not cast(#num as int) between 0 and 255)
return cast(0 as bit)
if (len(#ip) - #pos <= 0)
set #ip = null
else
set #ip = NullIf(substring(#ip, #pos + 1, len(#ip) - #pos), '')
end
return cast (1 as bit)
end
go
select dbo.fnCheckIP('127.0.0.1')
select dbo.fnCheckIP('127.0.0.300')
This solution is similar to Paulo's but using either approach will require getting rid of the comma character because isnumeric allows commas which will throw a cast to int error.
CREATE FUNCTION fn_ValidateIP
(
#ip varchar(255)
)
RETURNS int
AS
BEGIN
DECLARE #Result int = 0
IF
#ip not like '%,%' and
len(#ip) <= 15 and
isnumeric(PARSENAME(#ip,4)) = 1 and
isnumeric(PARSENAME(#ip,3)) = 1 and
isnumeric(PARSENAME(#ip,2)) = 1 and
isnumeric(PARSENAME(#ip,1)) = 1 and
cast(PARSENAME(#ip,4) as int) between 1 and 255 and
cast(PARSENAME(#ip,3) as int) between 0 and 255 and
cast(PARSENAME(#ip,2) as int) between 0 and 255 and
cast(PARSENAME(#ip,1) as int) between 0 and 255
set #Result = 1
ELSE
set #Result = 0
RETURN #Result
END
select dbo.fn_ValidateIP('127.0.0.1')
This may not be entirely practical, but one way would be to store the converted string ###-###-###-### into a binary(4) data type. Let the interface fuss around with hyphens and deal with converting the four numbers to binary and back (and this could probably even be done by a caluclated column.) A bit extreme, yes, but with binary(4) you will always be able to turn it into an IP address.
At last about 10 yrs after Oracle, sqlserver got native compilation (with limitations)
ALTER function fn_ValidateIPv4
(
#ip varchar(255)
)
RETURNS int
--WITH EXECUTE AS OWNER, SCHEMABINDING, NATIVE_COMPILATION
AS
BEGIN
--ATOMIC WITH (TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'us_english')
/* only sql2016 native Compilation **/
DECLARE #len_ip as int;
SET #len_ip = len(#ip);
DECLARE #firstBlock varchar(4) = '';
DECLARE #secondBlock varchar(4) = '';
DECLARE #thirdBlock varchar(4) = '';
DECLARE #fourthBlock varchar(4) = '';
DECLARE #countDot as smallint = 0;
DECLARE #l_i as smallint = 0;
DECLARE #l_curChar varchar(1) = 'X';
DECLARE #Result int = 0
IF (#len_ip <= 15)
BEGIN
WHILE (#l_i < #len_ip)
BEGIN
set #l_i += 1;
set #l_curChar = substring(#ip,#l_i,1);
if #l_curChar = '.'
SET #countDot += 1
ELSE
BEGIN
IF #l_curChar IN ( '0','1','2','3','4','5','6','7','8','9' )
BEGIN
IF #countDot = 0
SET #firstBlock = #firstBlock + #l_curChar;
IF #countDot = 1
SET #secondBlock = #secondBlock + #l_curChar;
IF #countDot = 2
SET #thirdBlock = #thirdBlock + #l_curChar;
IF #countDot = 3
SET #fourthBlock = #fourthBlock + #l_curChar;
IF #countDot > 3
set #firstBlock = 'AAA'; -- force error
END
ELSE set #firstBlock = 'AAA'; -- force error
END;
END;
IF ( #countDot = 3 and
cast(#fourthBlock as int) between 1 and 255 and
cast(#thirdBlock as int) between 0 and 255 and
cast(#secondBlock as int) between 0 and 255 and
cast(#firstBlock as int) between 0 and 255
)
set #Result = 1;
END;
/*
select dbo.fn_ValidateIPv4( '127.0.0.258' );
*/
RETURN #Result
END;
I had to remove not de-supported built functions isnumeric etc...