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;
Related
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.
I'm trying to change some string values in SQL using while loops and replace function.
I have two tables from where I get the values and formulas that I gotta change. The main problem is that when I execute the code, I can change the first matching pattern of the very first formula but the other patterns don't change.
I don't know if the problem is the way that I set the counters or the "Selects" used for searching values.
My code:
IF OBJECT_ID('tempdb..#TABLA_TEMP') IS NOT NULL BEGIN
DROP TABLE #TABLA_TEMP
END
IF OBJECT_ID('tempdb..#TABLE_VALUES') IS NOT NULL BEGIN
DROP TABLE #TABLE_VALUES
END
CREATE TABLE #TABLA_TEMP (
ID INT IDENTITY NOT NULL PRIMARY KEY,
NUMERO VARCHAR(max)
)
INSERT INTO #TABLA_TEMP(NUMERO)VALUES('X=''A01TGR.420.JHNB''+''A02TGR.421.ZASD''')
INSERT INTO #TABLA_TEMP(NUMERO)VALUES('X=''A08TGR.427.YUJK''+''A03TGR.422.CVBN''')
INSERT INTO #TABLA_TEMP(NUMERO)VALUES('X=''A04TGR.423.TYUI''+''A05TGR.424.QWER''')
CREATE TABLE #TABLE_VALUES (
ID INT IDENTITY NOT NULL PRIMARY KEY,
ID_INDICADOR INT,
CODIGO VARCHAR(max),
MtoValor DECIMAL(18,2)
)
INSERT INTO #TABLE_VALUES(ID_INDICADOR, CODIGO, MtoValor) VALUES (19520, 'A01TGR.420.JHNB', 50.00)
INSERT INTO #TABLE_VALUES(ID_INDICADOR, CODIGO, MtoValor) VALUES (19521, 'A02TGR.421.ZASD', 25.00)
INSERT INTO #TABLE_VALUES(ID_INDICADOR, CODIGO, MtoValor) VALUES (19522, 'A03TGR.422.CVBN', 15.00)
INSERT INTO #TABLE_VALUES(ID_INDICADOR, CODIGO, MtoValor) VALUES (19523, 'A04TGR.423.TYUI', 65.00)
INSERT INTO #TABLE_VALUES(ID_INDICADOR, CODIGO, MtoValor) VALUES (19524, 'A05TGR.424.QWER', 30.00)
INSERT INTO #TABLE_VALUES(ID_INDICADOR, CODIGO, MtoValor) VALUES (19527, 'A08TGR.427.YUJK', 45.00)
select * from #TABLA_TEMP
--select * from #TABLE_VALUES
DECLARE #counter int
SET #counter = 1
DECLARE #counterInterno int
SET #counterInterno = 1
WHILE(#counter <= (SELECT MAX(ID) FROM #TABLA_TEMP)) BEGIN
DECLARE #MatchExpression VARCHAR(max)
SET #MatchExpression = (''+ CAST(((SELECT CODIGO FROM #TABLE_VALUES
WHERE ID = #counter)) AS VARCHAR) +'')
--WHILE 1 = 1
WHILE(#counterInterno <= (SELECT MAX(ID) FROM #TABLE_VALUES)) BEGIN
DECLARE #valorInterno VARCHAR(MAX)
SET #valorInterno = (''+ CAST(((SELECT MtoValor FROM #TABLE_VALUES V
WHERE V.ID = #counterInterno)) AS VARCHAR) +'')
DECLARE #RetVal varchar(max)
SET #RetVal = (SELECT REPLACE(NUMERO, #MatchExpression, #valorInterno)
FROM #TABLA_TEMP T WHERE T.ID = #counterInterno)
IF(#RetVal IS NOT NULL)
UPDATE #TABLA_TEMP
SET NUMERO = #RetVal
WHERE ID = #counter
ELSE
break
SET #counterInterno = #counterInterno + 1
SET #counter = #counter + 1
END
END
SELECT * FROM #TABLA_TEMP
At the end, the idea is to get something like this:
X='65'+'15'+'25'
Any help would be appreciated.
Try this:
SELECT ROW_NUMBER() OVER (ORDER BY t1.ID, t2.ID) As RowNo, t1.ID, t1.NUMERO, t2.CODIGO, t2.MtoValor
INTO #NewTemp
FROM #TABLA_TEMP t1 JOIN #TABLE_VALUES t2 ON t1.NUMERO LIKE '%' + t2.CODIGO + '%'
DECLARE #Counter int = 1, #ID as int, #Codigo varchar(max), #MtoValor decimal(18, 2)
WHILE (EXISTS (SELECT 1 FROM #NewTemp WHERE RowNo = #Counter))
BEGIN
SELECT #ID = nt.ID, #Codigo = nt.CODIGO, #MtoValor = nt.MtoValor
FROM #NewTemp nt
WHERE nt.RowNo = #Counter
UPDATE #TABLA_TEMP
SET NUMERO = REPLACE(NUMERO, #Codigo, CAST(#MtoValor AS varchar(25)))
WHERE ID = #ID
SET #Counter = #Counter + 1
END
SELECT *
FROM #TABLA_TEMP
For this:
ID | NUMERO
----+-----------------------
1 | X='50.00'+'25.00'
2 | X='45.00'+'15.00'
3 | X='65.00'+'30.00'
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;
COMMSTR1-NAC-NAM-P-C FCPANAM1-NAC-NAM-P-C CHAZEL1-NAT-CBM-P-C
I want to seperate the above string as (Required Output)
col1 col2 col3 col4 col5 col6
COMMSTR1 NAC-NAM-P-C FCPANAM1 NAC-NAM-P-C CHAZEL1 NAT-CBM-P-C
I've tried this.
SELECT Contact_assg_list_src,
Contact_Assg_List_Src =
(
case WHEN Contact_Assg_List_Src IS NOT NULL and Contact_Assg_List_Src <> ''
then left(Contact_Assg_List_Src,patindex('%[-]%',Contact_Assg_List_Src)-1)
ELSE Contact_Assg_List_Src
END),
(case WHEN Contact_Assg_List_Src IS NOT NULL and Contact_Assg_List_Src <> ''
then substring(Contact_Assg_List_Src,(Patindex('%[-]%',Contact_Assg_List_Src + ' ')-1),len(Contact_Assg_List_Src))
ELSE Contact_Assg_List_Src
END)
from dbo.FBMSRAW;
Which gives me output like
col1 col2
COMMSTR1 NAC-NAM-P-C FCPANAM1-NAC-NAM-P-C CHAZEL1-NAT-CBM-P-C
How can I check whether the string has space then separate the string based on that to
get required output?
If you want to do it efficiently in SQL server, I'd advise using a CLR function.
But if you have to do it in T-SQL, this function will achieve it (slowly, and in an increasingly inefficient way)
create function SplitString
(
#splitchar char(1),
#string varchar(500),
#index int
)
returns varchar(500)
as
begin
declare #split int, #start int, #loop bit, #i int, #ret varchar(500)
select #start = 0, #i = 0
select #split = charindex(#splitchar, #string, 0)
if #index>0
select #loop = 1
else
select #loop = 0
while #loop = 1
begin
select #start = #split+1
select #split = charindex(#splitchar, #string, #start+1)
if #split = 0
begin
select #split = len(#string)+1
end
select #i = #i + 1
if #i = #index
begin
select #loop = 0
end
end
if #split>#start
select #ret = substring(#string, #start, #split-#start)
else
select #ret = null
return #ret
end
select dbo.SplitString (' ', 'COMMSTR1-NAC-NAM-P-C FCPANAM1-NAC-NAM-P-C CHAZEL1-NAT-CBM-P-C', [0 based column number])
I have wrote the following script to suit your needs, but your self you need to add some more logic, understand the following script
Create a dummy table
CREATE TABLE TBL_TEMPSTRINGS(STRCOL VARCHAR(200),COL1 VARCHAR(50),
COL2 VARCHAR(50),COL3 VARCHAR(50))
Insert values from your table
INSERT INTO TBL_TEMPSTRINGS
SELECT Contact_assg_list_src From dbo.FBMSRAW
Create a stored procedure to update your dummy table columns, it takes your table name in a string(why you can replace your dummy table with temp table name if you have used)
CREATE PROC SP_SPLITWRODS(#TABLENAME VARCHAR(50),#COLCOUNT INT)
AS
BEGIN
DECLARE #QRY VARCHAR(500)
CREATE TABLE #TBL_TEMP(STRCOL VARCHAR(200))
DECLARE #STRCOL VARCHAR(200)
DECLARE #CURRINDEX INT
DECLARE #TEMP INT
DECLARE #COLINDEX INT
DECLARE #ROWID INT
DECLARE #STRLEN INT
DECLARE #TEMPVALUE VARCHAR(50)
DECLARE #LASTWORD BIT
--CURSOR FOR YOUR TEMP TABLE
DECLARE CUR_TEMP CURSOR LOCAL FOR SELECT STRCOL FROM #TBL_TEMP
--CONSTRUCT QRY FOR FILLING YOUR TABLE
SET #QRY='INSERT INTO #TBL_TEMP SELECT STRCOL FROM ' + #TABLENAME
--FILL TABLE
EXECUTE(#QRY)
OPEN CUR_TEMP
FETCH CUR_TEMP INTO #STRCOL
WHILE ##FETCH_STATUS = 0
BEGIN
SET #CURRINDEX=1
SET #COLINDEX=1
SET #LASTWORD=0
--GET ' ' INDEX
SET #TEMP=CHARINDEX(' ',#STRCOL,#CURRINDEX)
WHILE #TEMP > 0
BEGIN
--YOU WILL GET THE VALUE SEPERATED BY SPACE
SET #TEMPVALUE=SUBSTRING(#STRCOL,#CURRINDEX,#TEMP-#CURRINDEX)
--ADD MORE LOGIC TO UPDATE YOUR COLUMNS (YOUR EXTRA COLUMNS)
--CONTRUCT QRY TO UPDATE CORRESPONDING COL IN YOUR TABLE FOR THE ROW FETCHED
--THIS UPDATES ALL ROWS, YOU NEED TO ADD ONE WHERE CONDITION TO UPDATE THE ROW
SET #QRY='UPDATE ' + #TABLENAME + ' SET COL' + CAST(#COLINDEX AS VARCHAR) + '=''' + #TEMPVALUE + ''''
EXEC(#QRY)
--INCREMENT COL INDEX AFTER UPDATE OF LAST COLUMN
SET #COLINDEX=#COLINDEX+1
SET #CURRINDEX=#TEMP+1
SET #TEMP=CHARINDEX(' ',#STRCOL,#CURRINDEX)
IF #TEMP=0 AND #LASTWORD=0
BEGIN
SET #TEMP=LEN(#STRCOL)+1
SET #LASTWORD=1
END
END
FETCH CUR_TEMP INTO #STRCOL
END
CLOSE CUR_TEMP
DEALLOCATE CUR_TEMP
END
Execute your proc
EXEC SP_SPLITWRODS 'TBL_TEMPSTRINGS',1
See your updated dummy table
SELECT * FROM TBL_TEMPSTRINGS
Presently it is updates 3 columns split by the space, you need to add your own logic to update the columns based on the string you have received(seperated by space).
Hope it helps
First a function to split the text
create function [dbo].[f_split]
(
#param nvarchar(max),
#delimiter char(1)
)
returns #t table (val nvarchar(max), seq int)
as
begin
set #param += #delimiter
;with a as
(
select cast(1 as bigint) f, charindex(#delimiter, #param) t, 1 seq
union all
select t + 1, charindex(#delimiter, #param, t + 1), seq + 1
from a
where charindex(#delimiter, #param, t + 1) > 0
)
insert #t
select substring(#param, f, t - f), seq from a
option (maxrecursion 0)
return
end
go
Query to display the result, assuming there are max 6 'words'
declare #t table(txt nvarchar(500))
insert #t values ('COMMSTR1-NAC-NAM-P-C FCPANAM1-NAC-NAM-P-C CHAZEL1-NAT-CBM-P-C'),
('t1 t2 t3 t4 t5 t6')
select * from #t t
outer apply
(
select max(case when seq = 1 then val end) col1,
max(case when seq = 2 then val end) col2,
max(case when seq = 3 then val end) col3,
max(case when seq = 4 then val end) col4,
max(case when seq = 5 then val end) col5,
max(case when seq = 6 then val end) col6
from dbo.f_split(t.txt, ' ')
) b
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