SQL single row to multiple rows separated by comma - sql-server

I would like to get a list of data from SQL Server including the data separated by comma in new rows.
Note : I have only single column name DATA
I have a value like
DATA
new
old,yes,now
ok,for
no
My required output is:
DATA
new
old
yes
now
ok
for
no

What you need is a split functions , Just see if this works for you
CREATE FUNCTION FNC_SPLIT(#MYSTR VARCHAR(500), #DELIMITER CHAR(1))
RETURNS #MYTBL TABLE (idx smallint, value varchar(8000))
AS
BEGIN
DECLARE #RET VARCHAR(500)
DECLARE #INDEX INT
DECLARE #COUNTER smallint
--Get the first position of delimiter in the main string
SET #INDEX = CHARINDEX(#DELIMITER,#MYSTR)
SET #COUNTER = 0
--Loop if delimiter exists in the main string
WHILE #INDEX > 0
BEGIN
--extract the result substring before the delimiter found
SET #RET = SUBSTRING(#MYSTR,1, #INDEX-1 )
--set mainstring right part after the delimiter found
SET #MYSTR = SUBSTRING(#MYSTR,#INDEX+1 , LEN(#MYSTR) - #INDEX )
--increase the counter
SET #COUNTER = #COUNTER + 1
--add the result substring to the table
INSERT INTO #MYTBL (idx, value)
VALUES (#COUNTER, #RET)
--Get the next position of delimiter in the main string
SET #INDEX = CHARINDEX(#DELIMITER,#MYSTR)
END
--if no delimiter is found then simply add the mainstring to the table
IF #INDEX = 0
BEGIN
SET #COUNTER = #COUNTER + 1
INSERT INTO #MYTBL (idx, value)
VALUES (#COUNTER, #MYSTR)
END
RETURN
END
GO
declare #table table(dt varchar(100));
insert into #table values
('DATA'),
('new'),
('old,yes,now'),
('ok,for');
select * from #table
select value from #table t cross apply dbo.FNC_SPLIT(t.dt,',')

Related

How to get split string with quotation on each split item in SQL Server?

How to get split string with quotation on each split item in SQL Server? I have tried this
declare #departmentNames as varchar(max) = 'Account, hod'
--declare #departmentNames as varchar(max) = 'Account'+', '+'hod'
print #departmentNames
I get result like this => Account,hod
but I want it like this => 'Account', 'hod'
so that I could use it in
select *
from tblDepartment
where name in (select item from splitString(#departmentNames, ','))
I know if I use integers with id column it will work fine i.e => 1, 2, 3, 4 but I want to try it with strings.
So is there anyone who can help me with this?
You can use apply :
select td.*
from tblDepartment td cross apply
<shema>.splitString(#departmentNames, ',') spt(item) -- add schema name
where spt.item = td.name;
If you want string comparison, you can do concatenation.
Note : use Schema name while calling UDF function.
First create this function:
CREATE FUNCTION [dbo].[fn_Split]
(#String varchar(8000),
#Delimiter varchar(50))
RETURNS #temptable TABLE (items varchar(8000))
AS
BEGIN
/*
SELECT * FROM dbo.fn_Split('12345;thome', ';')
*/
DECLARE #idx int
DECLARE #slice varchar(8000)
DECLARE #delimiterLength int
SET #delimiterLength = len(#Delimiter)
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 (LTRIM(RTRIM(#slice)))
SET #String = RIGHT(#String, LEN(#String) - #idx - #delimiterLength + 1)
IF LEN (#String) = 0
BREAK
END
RETURN
END
After creating this function then you can test with below query.
It splits words with any delimiter you are passing
select items from dbo.fn_Split('ACCOUNT ,HOD',',')
select items from dbo.fn_Split('ACCOUNT ; HOD',';')
Then pass variable and and use join with this function.
Use table alias for easy understanding
declare #departmentNames as varchar(max) = ('Account, hod')
select t.*
from tblDepartment t
inner join
(Select items
from dbo.fn_Split (#departmentNames, ',')) A on t.name = A.items
I create temptable for testing and this query will return output like below

Get range of new record insert in SQL Server

I have send data from downstream to cloud services and it will insert to Cloud SQL Services.
But, currently the data is send up to 12 data per seconds for some hours. The data contains DeviceID, Timestamp, HexData etc. and will be save in tbl_highspeeddata. Trigger has been created to convert the value of Hex data to ASCII string on this table.
The converting is work good if the data come in with some interval. As for now, there is only less hex data converted as I'm currently stuck on how to make it select range of new row inserted from last get until latest and do converting one-by-one before update back to the column.
After it finish, it will take from the the first new data after previous last processed data until the latest inserted record and repeat converting.
I have tried INSTEAD OF trigger
SELECT TOP n [primaryKey], *
FROM table
ORDER BY [primaryKey] DESC
SELECT SCOPE_IDENTITY();
and all failed to convert and update every inserted row.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[HSHD_Data_Conversion]
ON [dbo].[HSHD]
AFTER INSERT
AS
BEGIN
/****** HSHD stand for High Speed Hex Data ******/
---------convert HEX to ASCII
DECLARE #ID INT
DECLARE #HEX VARCHAR(MAX)
SET #ID = (SELECT SCOPE_IDENTITY()) --(SELECT TOP 1 ID from HSHD ORDER BY DateCreated DESC)
SET #HEX = (select CONVERT(varbinary(max), Data, 2) from HSHD WHERE ID = #ID)
UPDATE HSHD
SET Data = #HEX
WHERE ID = #ID
---------split command, query and result
DECLARE #Delimiter VARCHAR(8000)
DECLARE #Item VARCHAR(8000)
DECLARE #ItemList VARCHAR(8000)
DECLARE #DelimIndex INT
DECLARE #RowID INT
DECLARE #counter INT
DECLARE #isQuery VARCHAR(1)
SET #RowID = (SELECT SCOPE_IDENTITY()) --(SELECT TOP 1 ID FROM HSHD ORDER BY ID DESC)
SET #ItemList = (SELECT Data FROM HSHD WHERE ID = #RowID)
SET #counter = 0
SET #Delimiter = ':'
SET #DelimIndex = CHARINDEX(#Delimiter, #ItemList, 0)
WHILE (#DelimIndex != 0)
BEGIN
SET #counter = #counter + 1
SET #Item = SUBSTRING(#ItemList, 0, #DelimIndex)
--ignore the first element
IF #counter != 1
BEGIN
SET #isQuery = CHARINDEX('?',#Item,0)
IF len(#Item) != 0
BEGIN
IF #isQuery != 0
BEGIN
INSERT INTO HSHD_Data(HSHD,Query) VALUES (#RowID,':' + #Item)
END
ELSE INSERT INTO HSHD_Data(HSHD,Command) VALUES (#RowID, ':' + #Item)
END
END
-- Set #ItemList = #ItemList minus one less item
SET #ItemList = SUBSTRING(#ItemList, #DelimIndex+1, LEN(#ItemList)-#DelimIndex)
SET #DelimIndex = CHARINDEX(#Delimiter, #ItemList, 0)
SET #counter = #counter + 1
END -- End WHILE
IF #Item IS NOT NULL -- At least one delimiter was encountered in #InputString
BEGIN
SET #Item = #ItemList
SET #isQuery = CHARINDEX('?',#Item,0)
IF len(#Item) != 0
BEGIN
IF #isQuery != 0
BEGIN
INSERT INTO HSHD_Data(HSHD,Query) VALUES (#RowID,':' + #Item)
END
ELSE INSERT INTO HSHD_Data(HSHD,Command) VALUES (#RowID, ':' + #Item)
END
END
ELSE
BEGIN
SET #isQuery = CHARINDEX('?',#ItemList,0)
IF #isQuery != 0
INSERT INTO HSHD_Data(HSHD,Query) VALUES (#RowID, #ItemList)
ELSE
INSERT INTO HSHD_Data(HSHD,Result) VALUES (#RowID, #ItemList)
END
END
My reference:
Instead Of
Newly Added Row
EDITED:
HSHD data before trigger run:
HSHD data after trigger run:
So, after trigger finish running and convert these 2 data, trigger will start grab for data after :SYSTem:ERRor! #STRing until the last and converted hex and update back ASCII value to the HEX data.

Need to insert breaks in strings of very column with ' ' or ','

I have a table that has one Column but over 100,000 rows
Col_Name
qwchijhuirhxnihdiuyfnx
dhjhfiurhncnmxmzjcoinrds
xnbxknsiiuncirnxknrxnxz
I need to insert a '.' or '$' or some marker after every 3rd character
Example of result needed:
Col_Name
qwc.hij.hui.rhx.nih.diu.yfn.x
dhj.hfi.urh.ncn.mxm.zjc.oin.rds.
xnb.xkn.sii.unc.irn.xkn.rxn.xz
I originally solved this with:
INSERT INTO New_Table
(
c1
,c2
,c3
)
SELECT
substring(CAST(Col_Name AS VARCHAR(MAX)),1,3) as C1
,substring(CAST(Col_Name AS VARCHAR(MAX)),4,3) as C2
,substring(CAST(Col_Name AS VARCHAR(MAX)),7,3) as C3
From Table_Name
This causes problems later in the script so the data must remain in one column but could be inserted into a new table as long as it was a new table with just one column
Here's a sqlfiddle starting point you can refactor http://sqlfiddle.com/#!6/ab6dd/1/0 using function and while loop.
You may be able to do something more efficient with regular expressions or SQLCLR if you need speed.
CREATE FUNCTION dotify (#input varchar(MAX))
RETURNS varchar(MAX)
AS
BEGIN
DECLARE #output varchar(MAX) = ''
declare #index int = 0
declare #length int
set #length = len(#input)
while #index <= #length
begin
SET #output = #output + substring(#input, #index, 1)
if (#index % 3) = 0 AND #index > 0
BEGIN
SET #output = #output +'.'
END
set #index = #index + 1
end
return(#output)
END
GO
select TOP 10000 col_name, dbo.dotify(col_name) FROM old_table
You can use TOP to limit the processing time to a few seconds so you can easily profile efficiency changes you make.

Conversion failed when converting the varchar value ',1,2,3' to data type int

This error results when attempting to use a comma delimited parameter in an IN condition
I'm passing a varchar parameter to a stored procedure that looks like this
,1,2,3
And I want to find out if it contains 1 (it doesn't always contain 1)
What's the easiest way to do that in TSQL ?
declare #Nums varchar(max)=',1,2,3'
if 1 in (#Nums) -- conversion error
BEGIN
select * from TestTable
END
You will need to use LIKE to see if the string contains the character 1. Note this will also match 12 or any string with the character '1' in it.
declare #Nums varchar(max)=',1,2,3'
if #Nums LIKE '%1%'
BEGIN
select * from TestTable
END
If you need to match the full number:
CREATE FUNCTION [dbo].[Split_String]
(
#ItemList NVARCHAR(4000),
#delimiter CHAR(1)
)
RETURNS #IDTable TABLE (Item VARCHAR(50))
AS
BEGIN
DECLARE #tempItemList NVARCHAR(4000)
SET #tempItemList = #ItemList
DECLARE #i INT
DECLARE #Item NVARCHAR(4000)
SET #tempItemList = REPLACE (#tempItemList, ' ', '')
SET #i = CHARINDEX(#delimiter, #tempItemList)
WHILE (LEN(#tempItemList) > 0)
BEGIN
IF #i = 0
SET #Item = #tempItemList
ELSE
SET #Item = LEFT(#tempItemList, #i - 1)
INSERT INTO #IDTable(Item) VALUES(#Item)
IF #i = 0
SET #tempItemList = ''
ELSE
SET #tempItemList = RIGHT(#tempItemList, LEN(#tempItemList) - #i)
SET #i = CHARINDEX(#delimiter, #tempItemList)
END
RETURN
END
DECLARE #Nums VARCHAR(MAX) = ',1,2,3'
DECLARE #NumberTable TABLE (item INT)
INSERT INTO #NumberTable
SELECT TRY_CAST(Item AS INT)
FROM dbo.Split_String(#Nums, ',')
IF (SELECT 1 FROM #NumberTable WHERE item = 1) = 1
BEGIN
select * from TestTable
END
You can use CHARINDEX.
declare #Nums varchar(max)=',1,2,3'
IF CHARINDEX(',1,', #Nums+',') > 0
BEGIN
select * from TestTable
END

How to insert a comma separated values to the column to a SQL table in a order same as passing order?

i written a code like below to insert a comma separated values to the tempTble.It is working but i need the values to be entered in a order same as am passing it to query.But here number are arranged in a numerical order and string values arranged according to alphabetical order .Example '7,6,5,1,2,Jack,Ana,Micky' but it is inserted to column in a order of '1,2,5,6,7,Ana,Jack,Micky'.
Can you please provide answer for this.
Thank you in advance
ALTER PROCEDURE [dbo].[usp_GetValuesFromBillingSystem]
(
#BillingSystemCode VARCHAR(max)
)
AS
BEGIN
DECLARE #planID varchar(max) = Null ;
SET #planID= #BillingSystemCode
DECLARE #tempTble Table (planID varchar(50) NULL);
while len(#planID ) > 0
begin
insert into #tempTble (planID ) values(left(#planID , charindex(',', #planID +',')-1))
set #planID = stuff(#planID , 1, charindex(',', #planID +','), '')
end
select * from #tempTble
END
www.aspdotnet-suresh.com/2013/07/sql-server-split-function-example-in.html
CREATE FUNCTION dbo.Split(#String nvarchar(4000), #Delimiter char(1))
RETURNS #Results TABLE (Items nvarchar(4000))
AS
BEGIN
DECLARE #INDEX INT
DECLARE #SLICE nvarchar(4000)
-- HAVE TO SET TO 1 SO IT DOESNT EQUAL Z
-- ERO FIRST TIME IN LOOP
SELECT #INDEX = 1
WHILE #INDEX !=0
BEGIN
-- GET THE INDEX OF THE FIRST OCCURENCE OF THE SPLIT CHARACTER
SELECT #INDEX = CHARINDEX(#Delimiter,#STRING)
-- NOW PUSH EVERYTHING TO THE LEFT OF IT INTO THE SLICE VARIABLE
IF #INDEX !=0
SELECT #SLICE = LEFT(#STRING,#INDEX - 1)
ELSE
SELECT #SLICE = #STRING
-- PUT THE ITEM INTO THE RESULTS SET
INSERT INTO #Results(Items) VALUES(#SLICE)
-- CHOP THE ITEM REMOVED OFF THE MAIN STRING
SELECT #STRING = RIGHT(#STRING,LEN(#STRING) - #INDEX)
-- BREAK OUT IF WE ARE DONE
IF LEN(#STRING) = 0 BREAK
END
RETURN
END

Resources