Related
I want to post a solution to a interesting problem I was facing in T-SQL.
The problem:
Compare two string fields based on a percent match.
In addition, the two strings may have the words in them translocated.
For example: "Joni Bravo" and "Bravo Joni". These two strings should return a match of 100%, which means that position is not relevant. Few more things worth noting are that this code is made to compare strings that have space as delimiter in them. If the first string doesnt have space the match is set to 100% without actual check. This was not developed, because the strings this function is ment to compare always contain two or more words. Also, it is written on MS SQL Server 2017 if that mathers.
So here is the solution, hope this helps anyone :)
gl
/****** Object: UserDefinedFunction [dbo].[STRCOMP] Script Date: 29/03/2018 15:31:45 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[STRCOMP] (
-- Add the parameters for the function here
#name_1 varchar(255),#name_2 varchar(255)
)
RETURNS float
AS
BEGIN
-- Declare the return variable and any needed variable here
declare #p int = 0;
declare #c int = 0;
declare #br int = 0;
declare #p_temp int = 0;
declare #emergency_stop int = 0;
declare #fixer int = 0;
declare #table1_temp table (
row_id int identity(1,1),
str1 varchar (255));
declare #table2_temp table (
row_Id int identity(1,1),
str2 varchar (255));
declare #n int = 1;
declare #count int = 1;
declare #result int = 0;
declare #total_result float = 0;
declare #result_temp int = 0;
declare #variable float = 0.0;
--clean the two strings from unwanted symbols and numbers
set #name_1 = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(#name_1,'!',''),' ',' '),'1',''),'2',''),'3',''),'4',''),'5',''),'0',''),'6',''),'7',''),'8',''),'9','');
set #name_2 = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(#name_2,'!',''),' ',' '),'1',''),'2',''),'3',''),'4',''),'5',''),'0',''),'6',''),'7',''),'8',''),'9','');
--check if the first string has more than one words inside. If the string does
--not have more than one words, return 100%
set #c = charindex(' ',substring(#name_1,#p,len(#name_1)));
IF(#c = 0)
BEGIN
RETURN 100.00
END;
--main logic of the operation. This is based on sound indexing and comparing the
--outcome. This loops through the string whole words and determines their soundex
--code and then compares it one against the other to produce a definitive number --showing the raw match between the two strings #name_1 and #name_2.
WHILE (#br != 2 or #emergency_stop = 20)
BEGIN
insert into #table1_temp(str1)
select substring (#name_1,#p,#c);
set #p = len(substring (#name_1,#p,#c))+2;
set #p = #p + #p_temp - #fixer;
set #p_temp = #p;
set #c = CASE WHEN charindex(' ',substring(#name_1,#p,len(#name_1))) = 0 THEN len(#name_1) ELSE charindex(' ',substring(#name_1,#p,len(#name_1))) END;
set #fixer = 1;
set #br = CASE WHEN charindex(' ',substring(#name_1,#p,len(#name_1))) = 0 THEN #br + 1 ELSE 0 END;
set #emergency_stop = #emergency_stop +1;
END;
set #p = 0;
set #br = 0;
set #emergency_stop = 0;
set #fixer = 0;
set #p_temp = 0;
set #c = charindex(' ',substring(#name_2,#p,len(#name_2)));
WHILE (#br != 2 or #emergency_stop = 20)
BEGIN
insert into #table2_temp(str2)
select substring (#name_2,#p,#c);
set #p = len(substring (#name_2,#p,#c))+2;
set #p = #p + #p_temp - #fixer;
set #p_temp = #p;
set #c = CASE WHEN charindex(' ',substring(#name_2,#p,len(#name_2))) = 0 THEN len(#name_2) ELSE charindex(' ',substring(#name_2,#p,len(#name_2))) END;
set #fixer = 1;
set #br = CASE WHEN charindex(' ',substring(#name_2,#p,len(#name_2))) = 0 THEN #br + 1 ELSE 0 END;
set #emergency_stop = #emergency_stop +1;
END;
WHILE((select str1 from #table1_temp where row_id = #n) is not null)
BEGIN
set #count = 1;
set #result = 0;
WHILE((select str2 from #table2_temp where row_id = #count) is not null)
BEGIN
set #result_temp = DIFFERENCE((select str1 from #table1_temp where row_id = #n),(select str2 from #table2_temp where row_id = #count));
IF(#result_temp > #result)
BEGIN
set #result = #result_temp;
END;
set #count = #count + 1;
END;
set #total_result = #total_result + #result;
set #n = #n + 1;
END;
--gather the results and transform them in a percent match.
set #variable = (select #total_result / (select max(row_count) from (
select max(row_id) as row_count from #table1_temp
union
select max(row_id) as row_count from #table2_temp) a));
RETURN #variable/4 * 100;
END
GO
PS: I decided to write it in a user-defined function just for the needs of my project.
I'm using #subno as Input. And I had to find the odd and even numbers. 16 is not a fix and it can be any other number. My question is how to find the odd and even number of my input?
Lastly, subno includes ( . ) dot at any position. e.g 123456.789123 I need to find the odd and even number of "123456" and the odd and even number of "789123" the dot ( . ) is the separator.
Once you find the odd for the left side, sum them up together. Once you find the even number for left side sum it up as well and then add the total odd to the total even values. That goes the same for the right side eg "789123".
Please help me. this is my 2nd week of trying to find the solution. Once you find all the total values for each side, multiply them together. example "123456" - total value of odd and even * the "789123" total value of odd and even.
It is for the the check digit validation. Validating the subscriber number. after validating through the calculation it should match the calculated reference number to the valid check digit number. It's the business rule. Kind of algorithm
create procedure ProcedureName
(#subno VARCHAR(16), --Input the 16 subscriber number
#result INT OUT,
)
as
begin
IF(LEN(#subno) <> 16)
SET #result = 1 -- INVALID RESULT
ELSE
IF(#subno % 2 = 0)
SET #result = #subno - even numbers
ELSE
SET #result = #subno --odd numbers
end
Please see below my sample work
-- this is the sample
create procedure ProcedureName
(
#subno VARCHAR(20), --Subscriber no
#result INT OUT, --result is invalid for 1, valid for 0
#payamt int
)
as
DECLARE #WA VARCHAR(2)
DECLARE #Weights varchar(9)
DECLARE #I INT
DECLARE #WD INT
DECLARE #WP INT
DECLARE #A INT
DECLARE #B INT
DECLARE #R INT
DECLARE #WR INT
SET #WR = 0
SET #R = 0
SET #A = 0
SET #B = 0
SET #WP = 0
SET #I = 0
BEGIN
IF (LEN(#subNo) = 7) AND (SUBSTRING(#subno,1,1) = '2') OR (SUBSTRING(#subno,1,1) = '9')
BEGIN
SET #result = 0 --VALID
END
ELSE IF(LEN(#subno) = 8) AND (SUBSTRING(#subno,1,1) = '2') OR
(SUBSTRING(#subno,1,1) = '9')
BEGIN
SET #result = 0 --VALID
END
ELSE IF(LEN(#subno) = 9)
BEGIN
SET #WA = SUBSTRING(#subno,1,2)
IF(#WA = '65')
set #result = 1 -- INVALID
else
BEGIN
SET #Weights = '12121212'
SET #WA = SUBSTRING(#subno,9,1)
SET #WD = 0
SET #I = 1
WHILE #I<9
BEGIN
SET #WP = cast(SUBSTRING(#Weights, #I,1)as int) * cast(SUBSTRING(#subno, #I, 1) as int)
IF(#WP > 9)
BEGIN
SET #A = SUBSTRING(CAST(#WP AS VARCHAR),1,1)
SET #B = SUBSTRING(CAST(#WP AS VARCHAR),2,1)
SET #WP = CAST(#A AS INT) + CAST(#B AS INT)
END
SET #WD = #WP + #WD
SET #I = #I + 1
END
SET #R = #WD % 10
IF(#R <> 0)
SET #WR = 10 - #R
ELSE
SET #WR = #R
IF(#WR <> CAST(#WA AS INT))
BEGIN
SET #result = 1 -- INVALID
END
ELSE
BEGIN
SET #result = 0 -- VALID
END
END
END
ELSE IF (LEN(#subno) = 10)
BEGIN
SET #I =1
SET #WD = 0
SET #Weights = '121212121'
SET #WA = SUBSTRING(#subno,10,1)
WHILE(#I < 10)
BEGIN
SET #WP = CAST(SUBSTRING(#Weights, #I, 1)AS INT) * CAST(SUBSTRING(#subno, #I, 1) AS INT)
IF(#WP > 9)
BEGIN
SET #A = SUBSTRING(CAST(#WP AS VARCHAR),1,1)
SET #B = SUBSTRING(CAST(#WP AS VARCHAR),2,1)
SET #WP = CAST(#A AS INT) + CAST(#B AS INT)
END
SET #WD = #WP + #WD
SET #I = #I + 1
END
SET #R = #WD % 10
IF(#R <> 0)
SET #WR = 10 - #R
ELSE
SET #WR = #R
IF (#WR<> #WA)
BEGIN
SET #result = 1 -- INVALID
END
ELSE
BEGIN
SET #result = 0 -- VALID
END
END
ELSE
SET #result = 1 -- INVALID
END
Split the values which u get . Then iterate iver each side and add them. Please see the sample below.
declare #v varchar (16) , #num1 varchar(20) , #num2 varchar(20)
set #v = '1234567.78906656'
select #num1 = substring(#v,0,charindex('.',#v))
select #num2 = substring(#v,charindex('.',#v)+1,len(#v))
--select #num1 = convert(int, substring(#v,0,charindex('.',#v)))
--select #num2 = substring(#v,charindex('.',#v)+1,len(#v))
declare #index int = 1 ,#len INT , #char CHAR
declare #TotalOddL int = 0
declare #TotalEvenL int = 0
DECLARE #FullTotL INT = 0
declare #TotalOddR int = 0
declare #TotalEvenR int = 0
DECLARE #FullTotR INT = 0
DECLARE #TEMP INT
set #len= LEN(#num1)
WHILE #index <= #len
BEGIN
set #char = SUBSTRING(#num1, #index, 1)
SET #TEMP = cast(#char as int)
IF(#TEMP % 2 = 0)
SET #TotalEvenL = #TotalEvenL + #char
else
SET #TotalOddL = #TotalOddL + #char
SET #FullTotL = #TotalEvenL + #TotalOddL
SET #index= #index+ 1
END
Select 'LeftSide total' , #FullTotL
Select 'Left Side odd' , #TotalOddL
Select 'Left Side Even' , #TotalEvenL
SET #index = 1
set #len= LEN(#num2)
WHILE #index <= #len
BEGIN
set #char = SUBSTRING(#num2, #index, 1)
SET #TEMP = cast(#char as int)
IF(#TEMP % 2 = 0)
SET #TotalEvenR= #TotalEvenR + #char
else
SET #TotalOddR = #TotalOddR + #char
SET #FullTotR = #TotalEvenR + #TotalOddR
SET #index= #index+ 1
END
select 'TotalRSide' , #FullTotR
select 'RsideOdd' , #TotalOddR
select 'RSideEven' , #TotalEvenR
select 'Multiplied value' , #FullTotR * #FullTotL
create or replace procedure prc_even_odd(i_number in number, o_result out varchar2)
as
begin
if (mod(i_number,2) = 0) then
o_result := 'EVEN';
else
o_result := 'ODD';
end prc_even;
This was my first attempt at a SQL function. I wrote it in VB and it works like a charm. When I translated it to SQL Server, it returns not what I expect. What the function is intended to do is to return a percentage match of two strings.
How I expected it to function is this:
accept two strings, compare the two, and based on my rating values, return a percentage of the match value...matchscore/max possiblescore
The length of the larger string is multiplied by 3. This is the max possiblescore.
Go character by character of the first string and find that character in the second string.
If the character is found in the same position in the second string, add three to the matchscore and move on to the next letter.
If the character is found in the second word, but not in the same position, add one to match score and move on to the next character.
If the character is not found in the second string, add nothing and move on to the next character.
Divide the matchscore by the max possiblescore. This returns a decimal value. I read RETURN only returns an integer, so I multiplied the division result by 100.
An example of what I expected is I compare "CAT" to "CART". My expected return is 7/12...0.58. Instead, I get 0. If I compare "CAT" to "CAT", I expect 9/9...1.00. Instead, I get 2.
(Note from 9/17/2014: I appreciate your input. I used what you suggested, and did one more major change, that doesn't affect what I asked about, other than getting the correct final answer is that I got rid of the second While Loop. Instead, I search for #strLetter in #strWord2. If it is found, then, I look to see if it is in the same position in #strWord2 as #strWord1. If it is, then I add 3, if not, I add 1. This sped up the function and made the count accurate.
Here is the code:
CREATE FUNCTION [dbo].[CompareWords]
(#strWord1 VARCHAR(2000), #strWord2 VARCHAR(2000))
RETURNS DECIMAL
AS
BEGIN
SET #strWord1 = UPPER(#strWord1)
SET #strWord2 = UPPER(#strWord2)
DECLARE #intLength INT
IF LEN(#strWord1) >= LEN(#strWord2)
BEGIN
SET #intLength = LEN(#strWord1)
END
ELSE
BEGIN
SET #intLength = LEN(#strWord2)
END
DECLARE #iWordLoop1 INT
DECLARE #iWordLoop2 INT
DECLARE #intWordLoop2 INT
DECLARE #intWordScore INT
DECLARE #intLetterScore INT
SET #intWordScore = 0
SET #intWordLoop2 = Len(#strWord2)
DECLARE #strLetter VARCHAR(1000)
DECLARE #count1 INT
SET #count1 = 0
SET #iWordLoop1 = Len(#strWord1)
WHILE (#count1 < #iWordLoop1)
BEGIN
SET #strLetter = SUBSTRING(#strWord1, #count1+1, 1)
SET #intLetterScore = 0
DECLARE #count2 INT
SET #count2 = 0
SET #iWordLoop2 = Len(#strWord2)
WHILE (#count2 < #iWordLoop2)
BEGIN
If #strLetter = SUBSTRING(#strWord2, #count2+1, 1)
BEGIN
If #iWordLoop1 = #iWordLoop2
BEGIN
SET #intLetterScore = 3
SET #iWordLoop2 = Len(#strWord2)
END
ELSE
BEGIN
SET #intLetterScore = 1
END
END
SET #intWordScore = #intWordScore + #intLetterScore
SET #count2 = (#count2 + 1)
END
SET #count1 = (#count1 + 1)
END
DECLARE #sinScore DEC
SET #sinScore = (#intWordScore / (3 * #intLength)) * 100
RETURN #sinSCore
END;
The most significant changes I made were to
reset the intLetterScore to 0 after it's been used in the intWordScore calculation. Without it being reset, the same value was being used each time the inner loop and the character was not matched.
move the multiplication by 100 into the
brackets in the calculation of sinScore.
As referred to in a previous post, because you are doing integer multiplication, the decimal portion is truncated from the calculation. By growing the wordScore by a factor of 100, it is much more likely to be larger than the length and yield a result which is non-zero.
Multiplying outside the brackets has the multiplies the integer result of the division score by length. If this answer is already zero, then the multiplication result is also zero.
Other changes I made are commented in the code: the variable intWordLoop2 has no effect on the calculation and can be removed; strLetter can be declared as a Char(1) instead of VarChar(1000).
CREATE FUNCTION [dbo].[CompareWords]
(#strWord1 VARCHAR(2000), #strWord2 VARCHAR(2000))
RETURNS DECIMAL
AS
BEGIN
SET #strWord1 = UPPER(#strWord1)
SET #strWord2 = UPPER(#strWord2)
--Set #intLength (maxLength as len of word1 or word2)
DECLARE #intLength INT --maxLength
IF LEN(#strWord1) >= LEN(#strWord2)
BEGIN
SET #intLength = LEN(#strWord1)
END
ELSE
BEGIN
SET #intLength = LEN(#strWord2)
END
DECLARE #iWordLoop1 INT, #iWordLoop2 INT--, #intWordLoop2 INT --This variable doesn't impact the calculation
DECLARE #intWordScore INT
DECLARE #intLetterScore INT
SET #intWordScore = 0
--SET #intWordLoop2 = Len(#strWord2)--this value is not used anywhere else, so removing makes no difference.
--DECLARE #strLetter VARCHAR(1000)
DECLARE #strLetter CHAR(1)--there is no need for 1000 characters since we're only ever assigning a single character to this
DECLARE #count1 INT
SET #count1 = 0
SET #iWordLoop1 = Len(#strWord1)
WHILE (#count1 < #iWordLoop1)
BEGIN
SET #strLetter = SUBSTRING(#strWord1, #count1+1, 1)
SET #intLetterScore = 0
DECLARE #count2 INT
SET #count2 = 0
SET #iWordLoop2 = Len(#strWord2)
WHILE (#count2 < #iWordLoop2)
BEGIN
If #strLetter = SUBSTRING(#strWord2, #count2+1, 1)
BEGIN
If #iWordLoop1 = #iWordLoop2
BEGIN
SET #intLetterScore = 3
SET #iWordLoop2 = Len(#strWord2)
END
ELSE
BEGIN
SET #intLetterScore = 1
END
END
SET #intWordScore = #intWordScore + #intLetterScore
SET #intLetterScore = 0
SET #count2 = (#count2 + 1)
END
SET #count1 = (#count1 + 1)
END
DECLARE #sinScore DEC
SET #sinScore = (#intWordScore*100 / (3 * #intLength))
RETURN #sinSCore
END;
select dbo.comparewords ('Cat','cart')
I just had to scour the internet for this code yet again so I figured I would put it here so I can find it a little faster the next time and hopefully you found it a little faster too :)
Check this.
The code below can check digit in all GTIN's (EAN8, EAN13, EAN14, UPC/A, UPC/E)
CREATE FUNCTION [dbo].[check_digit]
(
#GTIN VARCHAR(14)
)
RETURNS TINYINT
AS
BEGIN
DECLARE #Index TINYINT,
#Multiplier TINYINT,
#Sum TINYINT,
#checksum TINYINT,
#result TINYINT,
#GTIN_strip VARCHAR(13)
SELECT #GTIN_strip = SUBSTRING(#GTIN,1,LEN(#GTIN)-1);
SELECT #Index = LEN(#GTIN_strip),
#Multiplier = 3,
#Sum = 0
WHILE #Index > 0
SELECT #Sum = #Sum + #Multiplier * CAST(SUBSTRING(#GTIN_strip, #Index, 1) AS TINYINT),
#Multiplier = 4 - #Multiplier,
#Index = #Index - 1
SELECT #checksum = CASE #Sum % 10
WHEN 0 THEN '0'
ELSE CAST(10 - #Sum % 10 AS CHAR(1))
END
IF (SUBSTRING(#GTIN,LEN(#GTIN),1) = #checksum)
RETURN 1; /*true*/
RETURN 0; /*false*/
END
CREATE FUNCTION [dbo].[fn_EAN13CheckDigit] (#Barcode nvarchar(12))
RETURNS nvarchar(13)
AS
BEGIN
DECLARE #SUM int , #COUNTER int, #RETURN varchar(13), #Val1 int, #Val2 int
SET #COUNTER = 1 SET #SUM = 0
WHILE #Counter < 13
BEGIN
SET #VAL1 = SUBSTRING(#Barcode,#counter,1) * 1
SET #VAL2 = SUBSTRING(#Barcode,#counter + 1,1) * 3
SET #SUM = #VAL1 + #SUM
SET #SUM = #VAL2 + #SUM
SET #Counter = #Counter + 2;
END
SET #SUM=(10-(#SUM%10))%10
SET #Return = #BARCODE + CONVERT(varchar,((#SUM)))
RETURN #Return
END
And here's a MySQL implementation as well.
Note it requires a 13 digit UPC/EAN13 as input, so you should LPAD your input as required.
drop function if exists barcodify;
delimiter //
at the last digit.
create function barcodify(upc varchar(15))
returns varchar(15)
sql security invoker
begin
declare i, r, odd, even,result int;
set odd=0;
set even =0;
set i = length(upc);
while i > 0 do
set r = substring(upc, i, 1) ;
if(i % 2 >0) then set odd = odd + r;
else set even = even + r;
end if;
set i = i - 1;
end while;
set result = (3*odd)+even;
if result % 10 =0 then return 0;
else return (10 - (result %10));
end if;
end //
delimiter ;
Here's my implementation of a function in Oracle.
CREATE OR REPLACE FUNCTION GenerateCheckDigit(pUPC IN VARCHAR2) RETURN INT
IS
vCheckDigit INT;
BEGIN
WITH barcodeData AS
(
SELECT pUPC barcode FROM dual
)
SELECT
10-REPLACE(MOD(SUM(SUBSTR(barcode, -LEVEL, 1) * DECODE(MOD(LEVEL-1, 2), 1, 1, 3)),10),0,10) INTO vCheckDigit
FROM barcodeData
CONNECT BY LEVEL <= LENGTH(barcode);
RETURN vCheckDigit;
END;
To calculate the last digit.
https://segovoni.medium.com/sql-server-function-to-calculate-gs1-barcode-check-digit-d55b478ff645
CREATE FUNCTION dbo.udf_GetGS1EAN13CheckDigit
(
#ACode AS VARCHAR(12)
)
RETURNS SMALLINT
AS BEGIN
/*
Author: Sergio Govoni
Notes: Calculate the check-digit of a GS1 EAN13 code
Version: 1.0
*/
DECLARE
#tmpCode AS VARCHAR(12)
,#tmpMulSup AS VARCHAR(8000)
,#tmp AS VARCHAR(8000)
,#i AS INT
,#j AS INT
,#z AS INT
,#SumDEven AS INT
,#SumDOdd AS INT
,#List AS VARCHAR(8000)
,#tmpList AS VARCHAR(8000)
,#CheckSum AS SMALLINT
SET #SumDEven = 0
SET #SumDOdd = 0
SET #List = ''
SET #tmpList = ''
SET #tmp = ''
SET #tmpCode = #ACode
/* 0. List builder */
SET #j = LEN(#tmpCode) + 1
SET #i = 1
WHILE (#i <= LEN(#tmpCode)) BEGIN SET #List = #List + '|' + LTRIM(RTRIM(STR(#j))) + ';' + SUBSTRING(#tmpCode, #i, 1) SET #j = (#j - 1) SET #i = (#i + 1) END /* 1. Add up the digits in even position */ SET #i = 1 SET #tmpList = #List WHILE (CHARINDEX('|', #tmpList) > 0)
BEGIN
SET #j = CHARINDEX('|', #tmpList)
SET #z = CHARINDEX(';', #tmpList)
IF (CAST(SUBSTRING(#tmpList, (#j + 1), (#z - (#j + 1))) AS INTEGER) % 2) = 0
BEGIN
SET #SumDEven = #SumDEven + CAST(SUBSTRING(#tmpList, (#z + 1), 1) AS INTEGER)
END
SET #tmpList = SUBSTRING(#tmpList, (#z + 2), LEN(#tmpList))
END
/* 2. Multiply the result of the previous step (the first step) to 3 (three) */
SET #SumDEven = (#SumDEven * 3)
/* 3. Add up the digits in the odd positions */
SET #i = 1
SET #tmpList = #List
WHILE (CHARINDEX('|', #tmpList) > 0)
BEGIN
SET #j = CHARINDEX('|', #tmpList)
SET #z = CHARINDEX(';', #tmpList)
IF (CAST(SUBSTRING(#tmpList, (#j + 1), (#z - (#j + 1))) AS INTEGER) % 2) <> 0
BEGIN
SET #SumDOdd = #SumDOdd + CAST(SUBSTRING(#tmpList, (#z + 1), 1) AS INTEGER)
END
SET #tmpList = SUBSTRING(#tmpList, (#z + 2), LEN(#tmpList))
END
/* 4. Add up the results obtained in steps two and three */
SET #CheckSum = (#SumDEven + #SumDOdd)
/* 5. Subtract the upper multiple of 10 from the result obtained in step four */
IF ((#CheckSum % 10) = 0)
BEGIN
/* If the result of the four step is a multiple of Ten (10), like
Twenty, Thirty, Forty and so on,
the check-digit will be equal to zero, otherwise the check-digit will be
the result of the fifth step
*/
SET #CheckSum = 0
END
ELSE BEGIN
SET #tmpMulSup = LTRIM(RTRIM(STR(#CheckSum)))
SET #i = 0
WHILE #i <= (LEN(#tmpMulSup) - 1)
BEGIN
SET #tmp = #tmp + SUBSTRING(#tmpMulSup, #i, 1)
IF (#i = LEN(#tmpMulSup) - 1)
BEGIN
SET #tmp = LTRIM(RTRIM(STR(CAST(#tmp AS INTEGER) + 1)))
SET #tmp = #tmp + '0'
END
SET #i = (#i + 1)
END
SET #CheckSum = CAST(#tmp AS INTEGER) - #CheckSum
END
RETURN #CheckSum
END;
CREATE FUNCTION sfn_ean_chkdigit(#barcode varchar(20))
RETURNS CHAR(1)
AS
BEGIN
DECLARE #chk_digit int, #chk int
DECLARE #num TABLE (num int)
IF LEN(#barcode) NOT IN (7, 12) RETURN NULL
INSERT INTO #num
SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL
SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL
SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12
SELECT #chk_digit = SUM(CONVERT(int, SUBSTRING(#barcode, LEN(#barcode) - num + 1, 1)) * CASE WHEN num % 2 = 1 THEN 3 ELSE 1 END)
FROM #num
WHERE num <= LEN(#barcode)
SELECT #chk_digit = (10 - (#chk_digit % 10)) % 10
RETURN CHAR(ASCII('0') + #chk_digit)
END
Num unico script
select lpad('123456789012',12,'0') || ( (r+1)*10 - soma )%10
from (select sum(v::int * case when i%2=0 then 3 else 1 end) soma,
round(sum(v::int * case when i%2=0 then 3 else 1 end)/10.0) r
from unnest(string_to_array(lpad('123456789012',12,'0'),null)) with ordinality d(v,i)
) a
I have a string 'some.file.name',I want to grab 'some.file'.
To do that,I need to find the last occurrence of '.' in a string.
My solution is :
declare #someStr varchar(20)
declare #reversedStr varchar(20)
declare #index int
set #someStr = '001.002.003'
set #reversedStr = reverse(#someStr)
set #index = len(#someStr) - charindex('.',#reversedStr)
select left(#someStr,#index)
Well,isn't it too complicated?I was just intented to using 'some.file' in a where-clause.
Anyone has a good idea?
What do you need to do with it?? Do you need to grab the characters after the last occurence of a given delimiter?
If so: reverse the string and search using the normal CHARINDEX:
declare #test varchar(100)
set #test = 'some.file.name'
declare #reversed varchar(100)
set #reversed = REVERSE(#test)
select
REVERSE(SUBSTRING(#reversed, CHARINDEX('.', #reversed)+1, 100))
You'll get back "some.file" - the characters up to the last "." in the original file name.
There's no "LASTCHARINDEX" or anything like that in SQL Server directly. What you might consider doing in SQL Server 2005 and up is great a .NET extension library and deploy it as an assembly into SQL Server - T-SQL is not very strong with string manipulation, whereas .NET really is.
A very simple way is:
SELECT
RIGHT(#str, CHARINDEX('.', REVERSE(#str)) - 1)
This will also work:
DECLARE
#test VARCHAR(100)
SET #test = 'some.file.name'
SELECT
LEFT(#test, LEN(#test) - CHARINDEX('.', REVERSE(#test)))
Take one ')'
declare #test varchar(100)
set #test = 'some.file.name'
select left(#test,charindex('.',#test)+charindex('.',#test)-1)
CREATE FUNCTION [dbo].[Instr] (
-------------------------------------------------------------------------------------------------
-- Name: [dbo].[Instr]
-- Purpose: Find The Nth Value Within A String
-------------------------------------------------------------------------------------------------
-- Revisions:
-- 25-FEB-2011 - HESSR - Initial Revision
-------------------------------------------------------------------------------------------------
-- Parameters:
-- 1) #in_FindString - NVARCHAR(MAX) - INPUT - Input Find String
-- 2) #in_String - NVARCHAR(MAX) - INPUT - Input String
-- 3) #in_StartPos - SMALLINT - INPUT - Position In The String To Start Looking From
-- (If Start Position Is Negative, Search Begins At The End Of The String)
-- (Negative 1 Starts At End Position 1, Negative 3 Starts At End Position Minus 2)
-- 4) #in_Nth - SMALLINT - INPUT - Nth Occurrence To Find The Location For
-------------------------------------------------------------------------------------------------
-- Returns: SMALLINT - Position Of String Segment (Not Found = 0)
-------------------------------------------------------------------------------------------------
#in_FindString NVARCHAR(MAX),
#in_String NVARCHAR(MAX),
#in_StartPos SMALLINT = NULL,
#in_Nth SMALLINT = NULL
)
RETURNS SMALLINT
AS
BEGIN
DECLARE #loc_FindString NVARCHAR(MAX);
DECLARE #loc_String NVARCHAR(MAX);
DECLARE #loc_Position SMALLINT;
DECLARE #loc_StartPos SMALLINT;
DECLARE #loc_Nth SMALLINT;
DECLARE #loc_Idx SMALLINT;
DECLARE #loc_FindLength SMALLINT;
DECLARE #loc_Length SMALLINT;
SET #loc_FindString = #in_FindString;
SET #loc_String = #in_String;
SET #loc_Nth = ISNULL(ABS(#in_Nth), 1);
SET #loc_FindLength = LEN(#loc_FindString+N'.') - 1;
SET #loc_Length = LEN(#loc_String+N'.') - 1;
SET #loc_StartPos = ISNULL(#in_StartPos, 1);
SET #loc_Idx = 0;
IF (#loc_StartPos = ABS(#loc_StartPos))
BEGIN
WHILE (#loc_Idx < #loc_Nth)
BEGIN
SET #loc_Position = CHARINDEX(#loc_FindString,#loc_String,#loc_StartPos);
IF (#loc_Position > 0)
SET #loc_StartPos = #loc_Position + #loc_FindLength
ELSE
SET #loc_Idx = #loc_Nth;
SET #loc_Idx = #loc_Idx + 1;
END;
END
ELSE
BEGIN
SET #loc_StartPos = ABS(#loc_StartPos);
SET #loc_FindString = REVERSE(#in_FindString);
SET #loc_String = REVERSE(#in_String);
WHILE (#loc_Idx < #loc_Nth)
BEGIN
SET #loc_Position = CHARINDEX(#loc_FindString,#loc_String,#loc_StartPos);
IF (#loc_Position > 0)
SET #loc_StartPos = #loc_Position + #loc_FindLength
ELSE
SET #loc_Idx = #loc_Nth;
SET #loc_Idx = #loc_Idx + 1;
END;
IF (#loc_Position > 0)
SET #loc_Position = #loc_Length - #loc_Position + (1 - #loc_FindLength) + 1;
END;
RETURN (#loc_Position);
END;
GO
Here is a shorter version
DECLARE #someStr varchar(20)
set #someStr = '001.002.003'
SELECT REVERSE(Substring(REVERSE(#someStr),CHARINDEX('.', REVERSE(#someStr))+1,20))