Split only after comma 3 times appear in sql.
I have string that looks like this
"abc,123,855,jkl,ddd,rrr,sss,999,777,kkk,jkl,ddd,rrr,sss,999"
getting this from db.
What I want returned is a string[] that was split after every 3rd comma, so it would look like this:
abc,123,855,
jkl,ddd,rrr,
sss,999,777,
kkk,jkl,ddd,
rrr,sss,999
Need this field to display in my JSP page, currently it taking more space of the table row.
Would really appreciate any help I can get!
Here is the complete example.
DECLARE #valueList varchar(8000)
DECLARE #pos INT
DECLARE #len INT
DECLARE #value varchar(8000)
SET #valueList = 'Pakistan,UAE,USA,UK,'
set #pos = 0
set #len = 0
WHILE CHARINDEX(',', #valueList, #pos+1)>0
BEGIN
set #len = CHARINDEX(',', #valueList, #pos+1) - #pos
set #value = SUBSTRING(#valueList, #pos, #len)
SELECT #pos, #len, #value
set #pos = CHARINDEX(',', #valueList, #pos+#len) +1
END
Solution for MS SQL. Assuming that your string with commas is in column in a table and there could be more rows with more different strings. Also assuming that last string remaining after parsing could have less than 3 commas.
Using two loops, First loop is checking if there are still rows to process. Second inner loop is checking if there is still remaining string with commas to process.
Original table with comma string column TableWithCommaStrings
Final table in this case only temp #Temp_3, but you can insert it anywhere.
IF OBJECT_ID('tempdb..#Temp_1') IS NOT NULL DROP TABLE #Temp_1
SELECT *
INTO #Temp_1
FROM TableWithCommaStrings
;
DECLARE #RowCount AS INT = 1;
WHILE #RowCount >= 1
BEGIN
IF OBJECT_ID('tempdb..#Temp_2') IS NOT NULL DROP TABLE #Temp_2
SELECT TOP 1 * /* Pick Only First line */
INTO #Temp_2
FROM #Temp_1;
WITH AA AS (SELECT TOP 1 * FROM #Temp_1 ) /* Delete that first line from Temp1*/
DELETE FROM AA;
/* Parse Column till last comma character remain there*/
DECLARE #CommaCharCount AS INT = 3;
WHILE #CommaCharCount >= 3
BEGIN
IF OBJECT_ID('tempdb..#Temp_3') IS NULL CREATE TABLE #Temp_3 (YourStringColumn VARCHAR(MAX));
INSERT INTO #Temp_3 /* Insert substring into temp3 based on Third Comman from beginning*/
SELECT substring(AA.YourStringColumn,1,(CharIndex(',',AA.YourStringColumn,Charindex(',',AA.YourStringColumn,CharIndex(',',AA.YourStringColumn)+1) +1))-1)
FROM #Temp_2 AS AA
UPDATE BB /*Remove part of string which has been procssed already in step above*/
SET BB.YourStringColumn = substring(YourStringColumn,((CharIndex(',',YourStringColumn,Charindex(',',YourStringColumn,CharIndex(',',YourStringColumn)+1) +1)+1)+1),LEN(YourStringColumn))
FROM #Temp_2 AS BB
/* Set comma counter */
SELECT #CommaCharCount= LEN(YourStringColumn) - LEN(REPLACE(YourStringColumn, ',', '')) FROM #Temp_2
END
IF (SELECT LEN(YourStringColumn) FROM #Temp_2) > 0
INSERT INTO #Temp_3 /* Last remaining Characters */
SELECT YourStringColumn
FROM #Temp_2
SELECT #RowCount = COUNT(*) FROM #Temp_1;
END
You can accomplish this far more easily in JSP using JSTL. In fact, since your actual need is just of display, you don't even need to create an array. Here is how to do it using the <c:forTokens> JSTL tag.
<c:set var="sqlString" value="abc,123,855,jkl,ddd,rrr,sss,999,777,kkk" />
<c:forTokens var="token" varStatus="tokenCounter" items="${sqlString}" delims=",">
<c:out value="${token}" />,
<c:if test="${tokenCounter.count % 3 == 0}">
<br />
</c:if>
</c:forTokens>
Related
Sample table
Record Number | Filter | Filters_Applied
----------------------------------------------
1 | yes | red, blue
2 | yes | green
3 | no |
4 | yes | red, red, blue
Is it possible to query all records where there are duplicate string values? For example, how could I query to pull record 4 where the string "red" appeared twice? Except in the table that I am dealing with, there are far more string values that can populate in the "filters_applied" column.
CLARIFICATION I am working out of Periscope and pulling data using SQL.
I assume that you have to check that in the logical page.
You can query the table with like '%red%'.
select Filters_Applied from table where Filters_Applied like '%red%';
You will get the data which has red at least one. Then, doing some string analysis in logic page.
In php, You can use the substr_count function to determine the number of occurrences of the string.
//the loop to load db query
while(){
$number= substr_count("Filters_Applied",red);
if($number>1){
echo "this".$Filters_Applied.">1"
}
}
for SQL-SERVER or other versions which can run these functions
Apply this logic
declare #val varchar(100) = 'yellow,blue,white,green'
DECLARE #find varchar(100) = 'green'
select #val = replace(#val,' ','') -- remove spaces
select #val;
select (len(#val)-len(replace(#val,#find,'')))/len(#find) [recurrence]
Create this Function which will parse string into rows and write query as given below. This will works for SQL Server.
CREATE FUNCTION [dbo].[StrParse]
(#delimiter CHAR(1),
#csv NTEXT)
RETURNS #tbl TABLE(Keys NVARCHAR(255))
AS
BEGIN
DECLARE #len INT
SET #len = Datalength(#csv)
IF NOT #len > 0
RETURN
DECLARE #l INT
DECLARE #m INT
SET #l = 0
SET #m = 0
DECLARE #s VARCHAR(255)
DECLARE #slen INT
WHILE #l <= #len
BEGIN
SET #l = #m + 1--current position
SET #m = Charindex(#delimiter,Substring(#csv,#l + 1,255))--next delimiter or 0
IF #m <> 0
SET #m = #m + #l
--insert #tbl(keys) values(#m)
SELECT #slen = CASE
WHEN #m = 0 THEN 255 --returns the remainder of the string
ELSE #m - #l
END --returns number of characters up to next delimiter
IF #slen > 0
BEGIN
SET #s = Substring(#csv,#l,#slen)
INSERT INTO #tbl
(Keys)
SELECT #s
END
SELECT #l = CASE
WHEN #m = 0 THEN #len + 1 --breaks the loop
ELSE #m + 1
END --sets current position to 1 after next delimiter
END
RETURN
END
GO
CREATE TABLE Table1# (RecordNumber int, [Filter] varchar(5), Filters_Applied varchar(100))
GO
INSERT INTO Table1# VALUES
(1,'yes','red, blue')
,(2,'yes','green')
,(3,'no ','')
,(4,'yes','red, red, blue')
GO
--This query will return what you are expecting
SELECT t.RecordNumber,[Filter],Filters_Applied,ltrim(rtrim(keys)), count(*)NumberOfRows
FROM Table1# t
CROSS APPLY dbo.StrParse (',', t.Filters_Applied)
GROUP BY t.RecordNumber,[Filter],Filters_Applied,ltrim(rtrim(keys)) HAVING count(*) >1
You didn't state your DBMS, but in Postgres this isn't that complicated:
select st.*
from sample_table st
join lateral (
select count(*) <> count(distinct trim(item)) as has_duplicates
from unnest(string_to_array(filters_applied,',')) as t(item)
) x on true
where x.has_duplicates;
Online example: http://rextester.com/TJUGJ44586
With the exception of string_to_array() the above is actually standard SQL
My teacher asks an algorithm that find all combinations. I have a set of data and the length can be variable. So combinations should be like this:
a
b
c
aa
ab
ac
...
ccbc
ccca
cccb
cccc
They will be stored in the "word" table that contains a single varchar field.
I did it with loop because I don't like recursivity and jt has better performance:
DROP PROCEDURE combi;
CREATE PROCEDURE combi
AS
BEGIN
DELETE FROM word
DECLARE #i BIGINT
DECLARE #j INT
DECLARE #word NVARCHAR(24)
DECLARE #str NVARCHAR(62)
DECLARE #combinations BIGINT
DECLARE #currentlength TINYINT
DECLARE #maxcurrentlength TINYINT
SET #maxcurrentlength=4
SET #str='azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN0123456789' -- length=62
SET #currentlength=1
-- loop on the length of the text
WHILE #currentlength<=#maxcurrentlength BEGIN
SET #combinations=POWER(62,#currentlength)
SET #i=0
-- get all combinations
WHILE i<#combinations BEGIN
SET #word=''
SET #j=0
-- generate word
WHILE #j<#currentlength BEGIN
SET #word=#word+SUBSTRING(#str, (FLOOR(#i / POWER(62,#currentlength-#j-1) ) % 62) +1, 1)
SET #j=#j+1
END
INSERT INTO word VALUES (#word)
SET #i=#i+1
END
SET #currentlength=#currentlength+1
END
END;
EXEC combi;
The problem is when I use a length of 8, my server crashes: it seems that POWER(62,#currentlength-#j-1) is the problem.
I'm slightly confused about how you ask the question. You ask to "find all combinations" which could very easily be done with CROSS JOIN. If you need to get a length of 4 then you join the table with available values to itself 4 times and you are pretty much done. If you need to get the strings in 1 field you could concatenate them in the select. Like this:
declare #values table (
value nvarchar(100))
insert #values values ('a'),('b'),('c')
select v1.value+v2.value+v3.value+v4.value
from #values v1 cross join
#values v2 cross join
#values v3 cross join
#values v4
order by v1.value+v2.value+v3.value+v4.value
Here is a generic solution using a recursive CTE:
CREATE TABLE t (i nchar(1))
INSERT INTO t VALUES ('a'),('b'),('c')
;WITH cte AS (
SELECT cast(i AS nvarchar(4000)) AS combo, 1 AS ct
FROM t
UNION ALL
SELECT cte.combo + t.i, ct + 1
FROM cte
CROSS JOIN t
WHERE ct <= 4 -- your maximum length
)
SELECT combo
FROM cte
ORDER BY ct, combo
SQL Fiddle.
You must be aware that the number of results grows exponentially with the maximum length, so performance deteriorates rapidly with growing maximum length.
You are likely overflowing the int type you are passing to POWER() as the documentation for power suggests POWER() returns the same type you feed it.
Try using:
SET #word=#word+SUBSTRING(#str, (FLOOR(#i / POWER(CAST(62 AS BIGINT),#currentlength-#j-1) ) % 62) +1, 1)
If you need to parameterise it so that you can set the required length then this algorithm would do it and it's more relational database orientated.
declare #characters table (character nchar(1))
declare #words table (word nvarchar(100))
insert #characters values ('a'),('b'),('c')
INSERT #words (word ) VALUEs ('')
DECLARE #Required_length int
DECLARE #length int
SET #Required_length = 4
SET #length = 0
WHILE #length <= #Required_length
BEGIN
SET #length = #length+1
INSERT #words (word )
SELECT w.word + c.character
FROM #words w JOIN #characters c ON LEN(w.word) = #length-1
END
SELECT word from #words where len(word) = #Required_length
Start with a zero length word
Add all the possible characters to the zero length word to get all
the one character words
Add all the possible characters to the end of all the one character
words to get all the two character words
Add all the possible characters to the end of all the two character words
to get all the three character words
etc....
You can make it run more efficiently by including the length as a column in the word table so that you don't need to calculate the lengths when you're filtering by them but as this has been set by your teacher I'm not going to do all your work for you
First insert of all characters
SET NOCOUNT ON;
create table ##chars (col char(1))
declare #i int
set #i=65
while #i<=90 /* A-Z */
begin
insert into ##chars values( CHAR(#i))
set #i=#i+1
end
set #i=97
while #i<=122 /* a-z */
begin
insert into ##chars values( CHAR(#i))
set #i=#i+1
end
set #i=48
while #i<=57 /* 0-9 */
begin
insert into ##chars values( CHAR(#i))
set #i=#i+1
end
Now, set number for combinations
create table ##result(word varchar(10))
declare #wide int
set #wide=4 /* set how many combinations are calculated */
insert into ##result select * from ##chars
while #wide>1
begin
begin tran w
insert into ##result select a.word+b.col from ##result a, ##chars b
commit tran w
set #wide=#wide-1
end
select * from ##result
/*
drop table ##chars
drop table ##result
*/
I have a table cell of type nvarchar(max) that typically looks like this:
A03 B32 Y660 P02
e.g. a letter followed by a number, separated by spaces. What I want to do is get a sum of all those numbers in a SQL procedure. Something rather simple in other languages, but I am fairly new to SQL and besides it seems to me like a rather clumsy language to play around with strings.
Aaanyway, I imagine it would go like this:
1) Create a temporary table and fill it using a split function
2) Strip the first character of every cell
3) Convert the data to int
4) Update target table.column set to sum of said temporary table.
So I got as far as this:
CREATE PROCEDURE [dbo].[SumCell] #delimited nvarchar(max), #row int
AS
BEGIN
declare #t table(data nvarchar(max))
declare #xml xml
set #xml = N'<root><r>' + replace(#delimited,' ','</r><r>') + '</r></root>'
insert into #t(data)
select
r.value('.','varchar(5)') as item
from #xml.nodes('//root/r') as records(r)
UPDATE TargetTable
SET TargetCell = SUM(#t.data) WHERE id = #row
END
Obviously, the first char stripping and conversion to int part is missing and on top of that, I get a "must declare the scalar variable #t" error...
Question is not very clear so assuming your text is in a single cell like A3 B32 Y660 P20 following snippet can be used to get the sum.
DECLARE #Cell NVARCHAR(400), #Sum INT, #CharIndex INT
SELECT #Cell = 'A3 B32 Y660 P20',#Sum=0
WHILE (LEN(LTRIM(#Cell))>0)
BEGIN
SELECT #CharIndex = CHARINDEX(' ',#Cell,0)
SELECT #Sum = #Sum +
SUBSTRING(#Cell,2,CASE WHEN #CharIndex>2 THEN #CharIndex-2 ELSE LEN(#Cell)-1 END )
SELECT #Cell = SUBSTRING(#Cell,#CharIndex+1,LEN(#Cell))
IF NOT (#CharIndex >0) BREAK;
END
--#Sum has the total of cell numbers
SELECT #Sum
I'm making the assumption that you really want to be able to find the sum of values in your delimited list for a full selection of a table. Therefore, I believe the most complicated part of your question is to split the values. The method I tend to use requires a numbers table, So I'll start with that:
--If you really want to use a temporary numbers table don't use this method!
create table #numbers(
Number int identity(1,1) primary key
)
declare #counter int
set #counter = 1
while #counter<=10000
begin
insert into #numbers default values
set #counter = #counter + 1
end
I'll also create some test data
create table #data(
id int identity(1,1),
cell nvarchar(max)
)
insert into #data(cell) values('A03 B32 Y660 P02')
insert into #data(cell) values('Y72 A12 P220 B42')
Then, I'd put the split functionality into a CTE to keep things clean:
;with split as (
select d.id,
[valOrder] = row_number() over(partition by d.cell order by n.Number),
[fullVal] = substring(d.cell, n.Number, charindex(' ',d.cell+' ',n.Number) - n.Number),
[char] = substring(d.cell, n.Number, 1),
[numStr] = substring(d.cell, n.Number+1, charindex(' ',d.cell+' ',n.Number) - n.Number)
from #data d
join #numbers n on substring(' '+d.cell, n.Number, 1) = ' '
where n.Number <= len(d.cell)+1
)
select id, sum(cast(numStr as int))
from split
group by id
I have a question related to matching strings in a MSSQL database. Basically, I have a table that contains ICD9 and CPT codes. The issue is that the format that these codes come in is usually incorrect (i.e. too many characters, missing decimal, etc...). I need to be able to lookup the description for each of these codes from a lookup table containing the correct code.
Because of the way these codes are structured I can do some type of "progressive" match to at least find the category of the code.
Lets say the correct code is something like: 306.98
And for this example lets pretend there are no other values between 306 and 307.
I would like to strip the decimal and look for a match, one character at a time, until one is not found. Then select the last matching string.
So 306,3069,3098, 306981, 3069812, etc... would match the string 306.98.
I hope that makes sense to everyone. I am not sure how I would even begin to do this, so any suggestion would be a great help.
One possible solution is to strip down the code to its basic element (306) and then do a like operator:
WHERE Code LIKE '306%'
Use FLOOR function to strip the decimal part and then use a LIKE operator in the WHERE clause.
Something like:
SELECT <COLUMN-LIST>
FROM <TABLE-NAME>
WHERE <THE-COLUMN> LIKE CAST(FLOOR(306.09) AS VARCHAR) + '%'
Here you have your example.You just need to convert value to nvarchar #string.
DECLARE #string AS NVARCHAR (MAX) = '306.98';
DECLARE #Table TABLE (
TextVal NVARCHAR (MAX));
INSERT INTO #Table ([TextVal])
SELECT '4444656'
UNION ALL
SELECT '30'
UNION ALL
SELECT '3069'
UNION ALL
SELECT '306989878787'
;
WITH numbers
AS (SELECT ROW_NUMBER() OVER ( ORDER BY (SELECT 1)) AS Number
FROM [sys].[objects] AS o1 CROSS JOIN [sys].[objects] AS o2),
Chars
AS (SELECT SUBSTRING(#string, [Number], 1) AS Let,
[Number]
FROM [numbers]
WHERE [Number] <= LEN(#string)),
Joined
AS (SELECT [Let],
CAST (1 AS BIGINT) AS Number
FROM chars
WHERE [Number] = 1
UNION ALL
SELECT [J].[Let] + CASE
WHEN [Chars].[Let] = '.' THEN '' ELSE [Chars].[Let]
END AS LEt,
Chars.[Number]
FROM [Joined] AS J
INNER JOIN
[Chars]
ON [Chars].[Number] = [J].[Number] + 1)
SELECT *
FROM #Table AS T
WHERE [T].[TextVal] IN (SELECT [Let]
FROM [Joined])
OR [T].[TextVal] LIKE '%'+(SELECT TOP 1 [Let] FROM
[Joined] ORDER BY [Number] DESC ) +'%'
;
Result will be:
TextVal
30
3069
306989878787
I was able to figure it out. Basically, I just needed to step through each character of the string and look for a match until once was no longer found. Thanks for the help!
/* ICD9 Lookup */
USE TSiData_Suite_LWHS_V11
DECLARE #String NVARCHAR (10)
DECLARE #Match NVARCHAR(10)
DECLARE #Substring NVARCHAR (10)
DECLARE #Description NVARCHAR(MAX)
DECLARE #Length INT
DECLARE #Count INT
SET #String = '309.99999999'
/* Remove decimal place from string */
SET #String = REPLACE(#String,'.','')
/* Get lenth of string */
SET #Length = LEN(#String)
/* Initialize count */
SET #Count = 1
/* Get Substring */
SET #Substring = SUBSTRING(#String,1,#Count)
/* Start processing */
IF (#Length < 1 OR #String IS NULL)
/* Validate #String */
BEGIN
SET #Description = 'No match found for string. String is not proper length.'
END
ELSE IF ((SELECT COUNT(*) FROM LookupDiseases WHERE REPLACE(LookupCodeDesc,'.','') LIKE #Substring + '%') < 1)
/* Check for at least one match */
BEGIN
SET #Description = 'No match found for string.'
END
ELSE
/* Look for matching code */
BEGIN
WHILE ((SELECT COUNT(*) FROM ICD9Lookup WHERE REPLACE(LookupCodeDesc,'.','') LIKE #Substring + '%') <> 1 AND (#Count < #Length + 1))
BEGIN
/* Update substring value */
SET #Substring = SUBSTRING(#String,1,#Count + 1)
/* Increment #Count */
SET #Count += 1
/* Select the first matching code and get description */
SELECT TOP(1) #Match = LookupCodeDesc, #Description = LookupName FROM ICD9Lookup WHERE REPLACE(LookupCodeDesc,'.','') LIKE #Substring + '%' ORDER BY LookupCodeDesc ASC
END
END
PRINT #Match
PRINT #Description
Ok, so I'm working on a basic search SPROC.
One of the Parameters is a search text (this will be the test the user enters in, words separated by spaces etc.)
Now all I need is to search these words on a single column in a table, BUT I want it to have ALL the keywords that were entered (at the moment all I can do is if 1 of them is there)
So is there a special SQL command that allows me to do this?
You can try something like this
check the occurances of the words required, and compare to the count of split words.
All issue i forsee is matches to partial words, but this might get you started
/*
ALTER FUNCTION [dbo].[SplitString]
(
#String VARCHAR(8000) ,
#Delimiter VARCHAR(10)
)
RETURNS #RetTable TABLE(
String varchar(1000)
)
AS
BEGIN
DECLARE #i INT ,
#j INT
SELECT #i = 1
WHILE #i <= LEN(#String)
BEGIN
SELECT #j = CHARINDEX(#Delimiter, #String, #i)
IF #j = 0
BEGIN
SELECT #j = LEN(#String) + 1
END
INSERT #RetTable SELECT SUBSTRING(#String, #i, #j - #i)
SELECT #i = #j + LEN(#Delimiter)
END
RETURN
END
*/
DECLARE #SearchString VARCHAR(MAX)
SELECT #SearchString = 'your,of'
DECLARE #SearchStringTable TABLE(
Words VARCHAR(MAX)
)
DECLARE #TABLE TABLE(
Col VARCHAR(MAX)
)
INSERT INTO #TABLE (Col)
SELECT
'On the Insert tab, the galleries include items that are designed to coordinate with the overall look of your document.'
INSERT INTO #TABLE (Col)
SELECT
'You can use these galleries to insert tables, headers, footers, lists, cover pages, and other document building blocks.'
INSERT INTO #TABLE (Col)
SELECT
'When you create pictures, charts, or diagrams, they also coordinate with your current document look.'
INSERT INTO #SearchStringTable (Words) SELECT * FROM dbo.SplitString(#SearchString,',')
SELECT t.Col,
COUNT(1) AS Number
FROM #TABLE t,
#SearchStringTable s
WHERE CHARINDEX(s.Words,t.Col) > 0
GROUP BY t.Col
HAVING COUNT(1) = (SELECT COUNT(1) FROM #SearchStringTable)
You need to split the #SEARCH_TEXT into the words and ideally store it in a temporary table #FILTER_TABLE with one column WORD containing the words. You can google for "sql comma split ...", but answer to this question might be helpful. This is also interesting.
Then you just use JOIN in your query to filter the rows. The simplest query then that would return all the matches would be:
SELECT t.*
f.WORD
FROM MyTable t
JOIN #FILTER_TABLE f
ON t.MyColumn = f.WORD --// = or LIKE operator
But if you provide an example of your data and expected result, people would could be more helpful.