return separate character from a string - sql

How to return all the characters from a string and count it in sql.
if the string is "how are you"
it should return
char count
2
h 1
o 2
w 1
a 1
r 1
e 1
y 1
u 1

You can use this script. It will give you exactly what you need.
This one counts just the letters in the string.
declare #c int
declare #ch varchar(10)
declare #str varchar(max)
set #str = 'how are you'
declare #letter int
declare #i int
set #i = 1
create table #tbl(ch varchar(10), cnt int)
while (#i <= len(#str))
begin
set #letter = 0
set #ch = substring(#str, #i, 1)
select #c = count(*) from #tbl
where ch = #ch
if ( (#ch >= 'a' and #ch <= 'z') or (#ch >= 'A' and #ch <= 'Z') )
begin
set #letter = 1
end
if (#c = 0)
begin
if (#letter = 1)
begin
insert into #tbl (ch, cnt) values (#ch, 1)
end
end
else
begin
update #tbl set cnt = cnt + 1 where ch = #ch
end
set #i = #i + 1
end
select * from #tbl
drop table #tbl
And if you want to count all chars (not just letters),
this makes it even easier. Use this script.
declare #c int
declare #ch varchar(10)
declare #str varchar(max)
set #str = 'how are you'
declare #i int
set #i = 1
create table #tbl(ch varchar(10), cnt int)
while (#i <= len(#str))
begin
set #ch = substring(#str, #i, 1)
select #c = count(*) from #tbl
where ch = #ch
if (#c = 0)
begin
insert into #tbl (ch, cnt) values (#ch, 1)
end
else
begin
update #tbl set cnt = cnt + 1 where ch = #ch
end
set #i = #i + 1
end
select * from #tbl
drop table #tbl

You can use a customer tsql function, see http://gallery.technet.microsoft.com/scriptcenter/T-SQL-Script-to-Split-a-308206f3.
And you can make a query solve your issue using group by and count statements ?

This will return the result set you have requested. It does this by taking each letter and adding it to a new row within a temporary table and then querying the results to return the counts for each occurrence of the character.
DECLARE #individual CHAR(1);
DECLARE #text NVARCHAR(200)
SET #text = 'how are you';
IF OBJECT_ID('tempdb..#tmpTable') IS NOT NULL
DROP TABLE #tmpTable
CREATE TABLE #tmpTable (letter char(1));
WHILE LEN(#text) > 0
BEGIN
SET #individual = SUBSTRING(#text, 1, 2)
INSERT INTO #tmpTable (letter) VALUES (#individual);
SET #text = SUBSTRING(#text, 2, LEN(#text))
END
SELECT letter, COUNT(*) AS [count]
FROM #tmpTable
GROUP BY letter;

Related

Implement the stored procedure iterative approach in a SQL manner

I am trying to implement convolution between two vectors v1 and v2. As part of that I have written a stored procedure with an iterative approach using while loops. Here is the below code as below. I am not able to think through how to do it using SQL as the stored procedure is inefficient w.r.t performance. Can somebody share your thoughts on this? Any inputs would be appreciated.
Idea behind writing the stored procedure:
https://software.intel.com/en-us/ipp-dev-reference-convolve
Table schema and sample input data:
CREATE TABLE AIRWork..TableA (idx INT, val INT);
CREATE TABLE AIRWork..TableB (idx INT, val INT);
INSERT INTO AIRWork..TableA
VALUES (0, -2), (1, 0), (2, 1), (3, -1), (4, 3);
INSERT INTO AIRWork..TableB
VALUES (0, 0), (1, 1);
Stored procedure:
ALTER PROCEDURE Calc_Convolved_Values_Test
AS
BEGIN
DECLARE #srclen1 INT
DECLARE #srclen2 INT
DECLARE #n INT = 0
DECLARE #k INT
DECLARE #m INT
DECLARE #SQL NVARCHAR(1000)
DECLARE #x int
DECLARE #xx int = 0
DECLARE #sum INT = 0
DECLARE #y int
DECLARE #yy int = 0
DECLARE #a INT = 0
DECLARE #b INT = 0
SELECT #srclen1 = COUNT(*) FROM AIRWork..TableA;
SELECT #srclen2 = COUNT(*) FROM AIRWork..TableB;
SET #m = #srclen1 + #srclen2 -1
WHILE #n < #m
BEGIN
SET #k = 0
SET #sum = 0
WHILE #k <= #n
BEGIN
SET #SQL = 'SELECT #x=val FROM AIRWork..TableA WHERE idx ='+CONVERT(VARCHAR(5),#k)
EXEC sp_executesql #SQL, N'#x int out', #xx out
SET #a = #xx
IF #n-#k < #srclen2
BEGIN
SET #SQL = 'SELECT #y=val FROM AIRWork..TableB WHERE idx ='+CONVERT(VARCHAR(5),#n-#k)
EXEC sp_executesql #SQL, N'#y int out', #yy out
SET #b = #yy
END
ELSE
BEGIN
SET #b = 0
END
SET #sum = #sum + #a*#b
SET #k = #k + 1
END
PRINT #sum
SET #n = #n + 1
END
END
GO
Sample output:
pDst[n] --> Please check the formula in the beginning of the question.
0
-2
0
1
-1
3
This procedure should do it:
ALTER PROCEDURE Calc_Convolved_Values_Test
AS
;WITH AllRows AS
(
SELECT idx, val, 0 as tbl FROM AIRWork..TableA
UNION ALL SELECT idx, val, 1 as tbl FROM AIRWork..TableB
)
, CombinedRows As
(
SELECT *,
ROW_NUMBER() OVER(ORDER BY tbl, idx)-1 As k,
COUNT(*) OVER(PARTITION BY 1) - 1 As n
FROM AllRows
)
SELECT ABDest.k As idx, SUM(A.val * B.val) As val
FROM CombinedRows AS ABDest
JOIN CombinedRows AS AB ON AB.k <= ABDest.k
LEFT JOIN AIRWork..TableA As A ON A.idx = AB.k
LEFT JOIN AIRWork..TableB As B ON B.idx = ABDest.k - AB.k
WHERE ABDest.k < ABDest.n
GROUP BY ABDest.k
ORDER BY ABDest.k
GO
FYI, I would not recommend using a whole table to store a single vector. You would be much better off storing all of your vectors in the same table and using a name or ID key column to separate them.

Sql Query To Find Relevant Match

I am trying to write a query that should return the following output:
val1 = 'GREAT'
val2 = 'TAGER'
See above have the same characters and it should return 'Exist' if the match is found. Otherwise, if there is a character missing, then 'Not exist'. I am using CASE to get the required output and was wondering if it could be done using SUBSTRING, CHARINDEX etc. Hoping to get a solution or idea to do so. Thanks.
You can make it as a function / procedure according to your needs.
DECLARE #S1 VARCHAR(100)
DECLARE #S2 VARCHAR(100)
SELECT #S1 = val1
,#S2 = val2
FROM <TABLE_NAME>
DECLARE #c CHAR(1)
DECLARE #i TINYINT
DECLARE #o1 VARCHAR(100) = ''
DECLARE #o2 VARCHAR(100) = ''
WHILE DataLength(#s1) > 0
BEGIN
SET #c = Left(#s1, 1)
SET #s1 = Substring(#s1, 2, len(#s1))
SET #i = 1
WHILE #i <= Len(#o1)
AND #c > substring(#o1, #i, 1)
SET #i += 1
SET #o1 = left(#o1, #i - 1) + #c + substring(#o1, #i, len(#o1))
END
WHILE DataLength(#s2) > 0
BEGIN
SET #c = Left(#s2, 1)
SET #s2 = Substring(#s2, 2, len(#s2))
SET #i = 1
WHILE #i <= Len(#o2)
AND #c > substring(#o2, #i, 1)
SET #i += 1
SET #o2 = left(#o2, #i - 1) + #c + substring(#o2, #i, len(#o2))
END
SELECT CASE
WHEN #o1 = #o2
THEN 'Exist'
ELSE 'Not Exist'
END
This is a custom script for you
Run this SP first
IF(OBJECT_ID('CharSplit')) IS NOT NULL
DROP PROCEDURE CharSplit;
GO
CREATE PROC CharSplit
#Words VARCHAR(MAX)
AS
BEGIN
IF OBJECT_ID('tempdb..#temp1') IS NOT NULL
DROP TABLE #temp1;
CREATE TABLE #temp1
(
letter CHAR(1), freq INT
);
IF OBJECT_ID('tempdb..#temp2') IS NOT NULL
DROP TABLE #temp2;
CREATE TABLE #temp2
(
letter CHAR(1), freq INT
);
DECLARE #t VARCHAR(MAX);
DECLARE #I INT;
--SET #Words = 'sanuantony';
SELECT #I = 0;
WHILE(#I < LEN(#Words) + 1)
BEGIN
SELECT #t = SUBSTRING(#words, #I, 1);
INSERT INTO #temp1
(letter, freq
)
VALUES
(#t, 0
);
SET #I = #I + 1;
END;
TRUNCATE TABLE #temp2;
INSERT INTO #temp2
(letter, freq
)
SELECT letter, COUNT(freq)
FROM #temp1
GROUP BY letter;
SELECT *
FROM #temp2
ORDER BY letter;
END;
Now Just try your business logic
DECLARE #t1 AS TABLE
(
letter CHAR(1), freq INT
);
DECLARE #t2 AS TABLE
(
letter CHAR(1), freq INT
);
INSERT INTO #t1
EXEC charSplit 'alammalay';
INSERT INTO #t2
EXEC charSplit 'malayalam';
IF(
(
SELECT COUNT(1)
FROM #t1
) =
(
SELECT COUNT(1)
FROM #t2
)
AND
(
SELECT COUNT(1)
FROM #t2
) =
(
(
SELECT COUNT(1)
FROM #t1
)
UNION
(
SELECT COUNT(1)
FROM #t2
)
)
)
SELECT 'Both are matching' AS result;
ELSE
SELECT 'Both are not matching' AS result;

T-SQL - compare strings char by char

I need to compare two strings character by character using T-SQL. Let's assume i have twor strings like these:
123456789
212456789
Every time the character DO NOT match, I would like to increase the variable #Diff +=1. In this case the first three characters differ. So the #Diff = 3 (0 would be default value).
Thank you for all suggestions.
for columns in table you don't want to use row by row approach, try this one:
with cte(n) as (
select 1
union all
select n + 1 from cte where n < 9
)
select
t.s1, t.s2,
sum(
case
when substring(t.s1, c.n, 1) <> substring(t.s2, c.n, 1) then 1
else 0
end
) as diff
from test as t
cross join cte as c
group by t.s1, t.s2
=>sql fiddle demo
This code should count the differences in input strings and save this number to counter variable and display the result:
declare #var1 nvarchar(MAX)
declare #var2 nvarchar(MAX)
declare #i int
declare #counter int
set #var1 = '123456789'
set #var2 = '212456789'
set #i = LEN(#var1)
set #counter = 0
while #i > 0
begin
if SUBSTRING(#var1, #i, 1) <> SUBSTRING(#var2, #i, 1)
begin
set #counter = #counter + 1
end
set #i = #i - 1
end
select #counter as Value
The below query compares, shows the different characters and bring you the count of differences
Declare #char1 nvarchar(1), #char2 nvarchar(1), #i int = 1, #max int
Declare #string1 nvarchar(max) = '123456789'
, #string2 nvarchar(max) = '212456789'
Declare #diff_table table (pos int , string1 nvarchar(50) , string2 nvarchar(50), Status nvarchar(50))
Set #max = (select case when len(#String1+'x')-1 > len(#string2+'x')-1 then len(#String1+'x')-1 else len(#string2+'x')-1 end)
while #i < #max +1
BEGIN
Select #char1 = SUBSTRING(#string1,#i,1), #char2 = SUBSTRING(#string2,#i,1)
INSERT INTO #diff_table values
(
#i,
case when UNICODE(#char1) is null then '' else concat(#char1,' - (',UNICODE(#char1),')') end,
case when UNICODE(#char2) is null then '' else concat(#char2,' - (',UNICODE(#char2),')') end,
case when ISNULL(UNICODE(#char1),0) <> isnull(UNICODE(#char2),0) then 'CHECK' else 'OK' END
)
set #i+=1
END
Select * from #diff_table
Declare #diff int = (Select count(*) from #diff_table where Status = 'Check')
Select #diff 'Difference'
The output will be like this:

Storing phone nos with only numbers and with "x" for extension?

I have a test function which would sanitize phone nos and allow only nos and characters "x" or "X" to be stored. I have it to where it does most of it other than it allows multiple x's which I don't want. Can anybody help me add it to the regular expression also let me know if you spot potential issues ?
CREATE Function [dbo].[RemoveAlphaCharacters](#Temp VarChar(1000))
Returns VarChar(1000)
AS
Begin
While PatIndex('%[^0-9,x,X]%', #Temp) > 0
Set #Temp = Stuff(#Temp, PatIndex('%[^0-9,x,X]%', #Temp), 1, '')
Return #TEmp
End
The problem with PATINDEX here is that it can't really determine that the pattern should change after it hits a string for the first time. So maybe this approach will be simpler:
CREATE FUNCTION [dbo].[RemoveAlphaCharacters]
(
#Temp VARCHAR(1000)
)
RETURNS VARCHAR(1000)
AS
BEGIN
DECLARE #i INT, #hitX BIT, #t VARCHAR(1000), #c CHAR(1);
SELECT #i = 1, #hitX = 0, #t = '';
WHILE #i <= LEN(#Temp)
BEGIN
SET #c = SUBSTRING(#Temp, #i, 1);
IF LOWER(#c) = 'x' AND #hitX = 0
BEGIN
SET #t = #t + #c;
SET #hitX = 1;
END
IF #c LIKE '[0-9]'
BEGIN
SET #t = #t + #c;
END
SET #i = #i + 1;
END
RETURN(#t);
END
GO
SELECT dbo.RemoveAlphaCharacters('401-867-9092');
SELECT dbo.RemoveAlphaCharacters('401-867-9092x32');
SELECT dbo.RemoveAlphaCharacters('401-867-9092x32x54');
Results:
4018679092
4018679092x32
4018679092x3254

sql-server-2005: How to perform a split on a pipe delimited string variable?

i have simple data coming in like this:
declare #string varchar(500) = "val1|val2|val3"
how could i split this out into a cte or something similar so i could user it in a later query:
select col1 from table where col2 = #valFromCTE
This is a helpful and simple way to query a delimited string as if it were a table.
Taken from:
http://www.mindsdoor.net/SQLTsql/ParseCSVString.html
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[fn_ParseCSVString]') and xtype in (N'FN', N'IF', N'TF'))
drop function [dbo].[fn_ParseCSVString]
GO
create function fn_ParseCSVString
(
#CSVString varchar(8000) ,
#Delimiter varchar(10)
)
returns #tbl table (s varchar(1000))
as
/*
select * from dbo.fn_ParseCSVString ('qwe,c,rew,c,wer', ',c,')
*/
begin
declare #i int ,
#j int
select #i = 1
while #i <= len(#CSVString)
begin
select #j = charindex(#Delimiter, #CSVString, #i)
if #j = 0
begin
select #j = len(#CSVString) + 1
end
insert #tbl select substring(#CSVString, #i, #j - #i)
select #i = #j + len(#Delimiter)
end
return
end
GO