I'm new to cursors,
How should I write my below code in cursor to pass column value to variable #str
Basically #str in below code is taking static value, need to pass table column values
DECLARE #str VARCHAR(1000),
#str1 VARCHAR(1000),
#str2 VARCHAR(1000),
#pos INT,
#counter INT
SET #str = '45 | 00055 | 9/30/2016 | Vodafone | Randy Singh | Newyork | Test Msg | TBL101 | PC | 1.00 | COMP101 | CS | 1.00.............. etc'
(Here i need to pass table column value like--- select name from Order so every time it takes new value)
--select #str = temp FROM OrderTemp
SET #counter = 0
SET #pos = 0
WHILE #counter <= 6
BEGIN
SET #pos = CHARINDEX('|', #str, #pos + 1)
SET #counter = #counter + 1
END
SET #str1 = SUBSTRING(#str, 1, #pos)
SET #str2 = SUBSTRING(#str, #pos+1, LEN(#str)-#pos)
insert into OrderInterface (name)(SELECT #str2)
insert into OrderInterface (Id)(SELECT #str1)
Input
#str :-- '45 | 00055 | 9/30/2016 | Vodafone | Randy Singh | Newyork | Test Msg | TBL101 | PC | 1.00 | COMP101 | CS | 1.00.............. etc'
Now i need to pass Input value from table like : Select name from tablename instead of static values.
Ouput
#str1 :-- '45 | 00055 | 9/30/2016 | Vodafone | Randy Singh | Newyork | Test Msg'
#str2 :-- 'TBL101 | PC | 1.00 | COMP101 | CS | 1.00.............. etc'
OK, Assuming #Temp looks something like this:
Then we can do the following:
;with cte as (
Select A.RN,B.*
From (Select *,RN = Row_Number() over(Order By (Select NULL)) From #Temp) A
Cross Apply [dbo].[udf-Str-Parse](A.Temp,' | ') B
)
-- Insert Into OrderInterface (Name,ID)
Select Name = (Select String1=Stuff((Select ' | ' + RetVal From cte Where RN=A.RN and RetSeq<=7 For XML Path ('')),1,3,'') )
,ID = (Select String1=Stuff((Select ' | ' + RetVal From cte Where RN=A.RN and RetSeq>7 For XML Path ('')),1,3,'') )
From cte A
Group By A.RN
Which Returns
The UDF if Needed
CREATE FUNCTION [dbo].[udf-Str-Parse] (#String varchar(max),#Delimiter varchar(10))
Returns Table
As
Return (
Select RetSeq = Row_Number() over (Order By (Select null))
,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>'+ Replace(#String,#Delimiter,'</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
);
--Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ')
I think what you are trying to do is find the 6th element in a string deliminated by |.
If that is the case you should not use a loop (as is always the case in SQL) instead in SQL Server you can use the STRING_SPLIT function (https://msdn.microsoft.com/en-us/library/mt684588.aspx) like this:
SELECT value
FROM STRING_SPLIT(#sql, ' | ')
OFFSET ROWS 5 FETCH FIRST 1 ROW ONLY
Related
Assume we have two below strings:
DECLARE #AllowedCardBoardIds NVARCHAR(MAX) = '1,2,3,4,5,6'
DECLARE #AllowedCardBoardIdsAccessTypes NVARCHAR(MAX) = '11,22,33,44,55,66'
Also, assume we have a function to split a string as a table.
It returns a sequence values
Select * FROM dbo.SplitString(',', #AllowedCardBoardIds)
-- result:
Value
------
1
2
3
4
5
6
Now I want to convert two string to table and merge them as follows:
Id | AccessType
--------------------
1 | 11
2 | 22
3 | 33
4 | 44
5 | 55
6 | 66
How should I do it?
I wrote a query as follows:
DECLARE #AllowedCardBoardsTable TABLE(
Id INT NOT NULL,
AccessType INT NOT NULL
)
INSERT INTO #AllowedCardBoardsTable
(
Id, AccessType
)
SELECT id.[Value], accessType.[Value]
FROM dbo.SplitString(',', #AllowedCardBoardIds) AS id
But I don't know how to fill AccessType column !
Please try the following solution.
SQL
DECLARE #AllowedCardBoardsTable TABLE(
Id INT NOT NULL,
AccessType INT NOT NULL
);
DECLARE #AllowedCardBoardIds NVARCHAR(MAX) = '1,2,3,4,5,6';
DECLARE #AllowedCardBoardIdsAccessTypes NVARCHAR(MAX) = '11,22,33,44,55,66';
DECLARE #separator CHAR(1) = ',';
;WITH rs AS
(
SELECT CardBoardIds = CAST('<root><r><![CDATA[' +
REPLACE(#AllowedCardBoardIds, #separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML)
, CardBoardIdsAccessTypes = CAST('<root><r><![CDATA[' +
REPLACE(#AllowedCardBoardIdsAccessTypes, #separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML)
)
, rs2 AS
(
SELECT rn = ROW_NUMBER() OVER(ORDER BY (t.c))
, Id = c.value('.', 'INT')
FROM rs
CROSS APPLY CardBoardIds.nodes('/root/r/text()') AS t(c)
)
, rs3 AS
(
SELECT rn = ROW_NUMBER() OVER(ORDER BY (t.c))
, Id = c.value('.', 'INT')
FROM rs
CROSS APPLY CardBoardIdsAccessTypes.nodes('/root/r/text()') AS t(c)
)
INSERT INTO #AllowedCardBoardsTable (Id, AccessType)
SELECT rs2.id, rs3.Id
FROM rs2 INNER JOIN rs3 ON rs3.rn = rs2.rn;
-- test
SELECT * FROM #AllowedCardBoardsTable;
Output
+----+------------+
| Id | AccessType |
+----+------------+
| 1 | 11 |
| 2 | 22 |
| 3 | 33 |
| 4 | 44 |
| 5 | 55 |
| 6 | 66 |
+----+------------+
I would suggest you use one of the built-in string-splitting methods, rather than trying to roll your own.
Unfortunately, current versions of SQL Server do not support STRING_SPLIT with an ordinal column. But in this case you can hack it with OPENJSON
DECLARE #AllowedCardBoardIds NVARCHAR(MAX) = '1,2,3,4,5,6';
DECLARE #AllowedCardBoardIdsAccessTypes NVARCHAR(MAX) = '11,22,33,44,55,66';
SELECT
id = acb.value,
AccessType = at.value
FROM OPENJSON('[' + #AllowedCardBoardIds + ']') acb
JOIN OPENJSON('[' + #AllowedCardBoardIdsAccessTypes + ']') at
ON at.[key] = acb.[key];
db<>fiddle
I strongly suggest you store your data properly normalized in the first place, such as in a table variable, temp table, or normal table.
I have a variable in my stored procedure `#param varchar', the parameter value will be like '333,445,443,222' or '555'
I need to store into as row in the #Employee table, Code column.
Expected output:
#Employee temp table:
Code
----
333
445
443
222
It will work with any SQL server version. User define table function
CREATE FUNCTION dbo.SplitString
(
#Value nvarchar(max),
#Delim nvarchar(5)
)
RETURNS TABLE
AS
RETURN ( SELECT [Value] FROM
(
SELECT [Value] = LTRIM(RTRIM(SUBSTRING(#Value, [Number],
CHARINDEX(#Delim, #Value + #Delim, [Number]) - [Number])))
FROM (SELECT Number = ROW_NUMBER() OVER (ORDER BY name)
FROM sys.all_columns) AS x WHERE Number <= LEN(#Value)
AND SUBSTRING(#Delim + #Value, [Number], DATALENGTH(#Delim)/2) = #Delim
) AS y
);
and then it can be used
DECLARE #param varchar(1000)
SET #param = '333,445,443,222'
SELECT value AS Code FROM dbo.SplitString(#param, ',');
Demo: http://sqlfiddle.com/#!18/9eecb/89486
Since SQL Server 2016, there has been a built-in function to do this:
select s.value
from string_split(#param, ',') s
I would recommend using it. The one downside to string_split() is that it does not provide ordering in the string. If ordering is important and there are no duplicates, then charindex() can be used. If there can be duplicates, then I recommend a recursive CTE.
Your problem can be solved with recursive CTE (need to know about maxrecursion):
create function my_split(#s nvarchar(max), #d nvarchar(1))
returns table return
with
r as (
select
iif(p > 0, left(#s, p - 1), #s) as s,
iif(p > 0, right(#s, len(#s) - p), '') as r
from (select charindex(#d, #s)) as a(p)
union all
select
iif(p > 0, left(r, p - 1), r),
iif(p > 0, right(r, len(r) - p), '')
from r
cross apply (select charindex(#d, r)) as a(p)
where r != ''
)
select s from r;
Output:
+----+-----------------+------+
| | param | code |
+----+-----------------+------+
| 1 | 333,445,443,222 | 333 |
| 2 | 333,445,443,222 | 445 |
| 3 | 333,445,443,222 | 443 |
| 4 | 333,445,443,222 | 222 |
| 5 | 555 | 555 |
+----+-----------------+------+
Demo.
I have a query to split the accounid and dbids between braces separately.
example: [14801].[42]
acid scid
14801 42
but I'm not able to separate after comma ,
example :
[27784].[41],[27781].[41],[27779].[41]
need a query to split this data into rows
you need to create function to split values into rows
create function [dbo].[udf_splitstring] (#tokens varchar(max),
#delimiter varchar(5))
returns #split table (
token varchar(200) not null )
as
begin
declare #list xml
select #list = cast('<a>'
+ replace(#tokens, #delimiter, '</a><a>')
+ '</a>' as xml)
insert into #split
(token)
select ltrim(t.value('.', 'varchar(200)')) as data
from #list.nodes('/a') as x(t)
return
end
select * from into #a udf_splitstring ('[27784].[41],[27781].[41],[27779].[41]',',')
output
[27784].[41]
[27781].[41]
[27779].[41]
coming result store in one temp table
SELECT TOKEN,REPLACE(REPLACE(SUBSTRING(TOKEN,0,CHARINDEX('.',TOKEN)),'[',''),']','') AS first_id
,REPLACE(REPLACE(REVERSE(SUBSTRING(REVERSE(TOKEN),0,CHARINDEX('.',REVERSE(TOKEN)))),'[',''),']','') AS second_id
FROM #a
output
TOKEN first_id second_id
[27784].[41] 27784 41
[27781].[41] 27781 41
[27779].[41] 27779 41
Try this:
DECLARE #START_ID VARCHAR(100)='[27784].[41],[27781].[41],[27779].[41]'
DECLARE #ID VARCHAR(MAX)
DECLARE #COUNT INT
DECLARE #TEMP TABLE(C1 VARCHAR(MAX))
WHILE( CHARINDEX(',',#START_ID))>0
BEGIN
INSERT INTO #TEMP SELECT SUBSTRING(#START_ID,0,CHARINDEX(',',#START_ID))
SET #START_ID=(SELECT REPLACE(#START_ID,(SUBSTRING(#START_ID,0,CHARINDEX(',',#START_ID)+1)),''))
END
INSERT INTO #TEMP SELECT #START_ID
SELECT C1,REPLACE(REPLACE(SUBSTRING(C1,0,CHARINDEX('.',C1)),'[',''),']','') AS SOURCE_ACCOUT_ID
,REPLACE(REPLACE(REVERSE(SUBSTRING(REVERSE(C1),0,CHARINDEX('.',REVERSE(C1)))),'[',''),']','') AS SOURCE_DATABASE_ID
FROM #TEMP
select n.ids.value ('id[1]','int') as accountid
,n.ids.value ('id[2]','int') as dbid
from (select cast (replace('<r><e><id>'+replace(replace(replace(
ids,'[',''),']',''),',','</id></e><e><id>')+
'</id></e></r>','.','</id><id>') as xml) as x
from mytable
) t
cross apply x.nodes ('/r/e') n(ids)
+-----------+------+
| accountid | dbid |
+-----------+------+
| 27784 | 41 |
+-----------+------+
| 27781 | 41 |
+-----------+------+
| 27779 | 41 |
+-----------+------+
| 28021 | 30 |
+-----------+------+
| 28024 | 30 |
+-----------+------+
| 29007 | 56 |
+-----------+------+
DDL + DML for demo
create table mytable (ids varchar(1000))
insert into mytable values
('[27784].[41],[27781].[41],[27779].[41]')
, ('[28021].[30],[28024].[30]')
, ('[29007].[56]')
Present column value
(Below is column value from temp table, value here is dynamically changing)
45 | 00055 | 9/30/2016 | Vodafone | Randy Singh | Newyork | Test Msg | TBL101 | PC | 1.00 | COMP101 | CS | 1.00.............. etc
Need to divide based on 7th PIPE i.e after Test Msg
Output should be
String1
45 | 00055 | 9/30/2016 | Vodafone | Randy Singh | Newyork | Test Msg
and (as a second string)
String 2
TBL101 | PC | 1.00 | COMP101 | CS | 1.00......... etc
Function
CREATE FUNCTION dbo.SUBSTRING_INDEX
(
#str NVARCHAR(4000),
#delim NVARCHAR(1),
#count INT
)
RETURNS NVARCHAR(4000)
WITH SCHEMABINDING
BEGIN
DECLARE #XmlSourceString XML;
SET #XmlSourceString = (SELECT N'<root><row>' + REPLACE( (SELECT #str AS '*' FOR XML PATH('')) , #delim, N'</row><row>' ) + N'</row></root>');
RETURN STUFF
(
((
SELECT #delim + x.XmlCol.value(N'(text())[1]', N'NVARCHAR(4000)') AS '*'
FROM #XmlSourceString.nodes(N'(root/row)[position() <= sql:variable("#count")]') x(XmlCol)
FOR XML PATH(N''), TYPE
).value(N'.', N'NVARCHAR(4000)')),
1, 1, N''
);
END
GO
DECLARE #EmpId NVARCHAR(1000)
select #EmpId = temp from OMSOrderTemp
SELECT dbo.SUBSTRING_INDEX(#EmpId, N'|', 7) AS Result;e
Here in Result only string1 is showing and only first row.
Spend time for you and happy that come with solution , I have modify the your function with own logic you can try this, This is table value function i.e this function will return Table
CREATE FUNCTION dbo.SUBSTRING_INDEX
(
#str NVARCHAR(4000),
#delim NVARCHAR(1),
#count INT
)RETURNS #rtnTable TABLE
(
FirstString NVARCHAR(2000),
SecondString NVARCHAR(2000)
)
AS
BEGIN
DECLARE #cnt INT=1;
DECLARE #subStringPoint INT = 0
WHILE #cnt <=#count
BEGIN
SET #subStringPoint=CHARINDEX(#delim,#str,#subStringPoint)+1
SET #cnt=#cnt+1
END
INSERT INTO #rtnTable
SELECT SUBSTRING(#str,0,#subStringPoint-1) ,SUBSTRING(#str,#subStringPoint+1,LEN(#str))
RETURN
END
To call this function
DECLARE #s varchar(MAX)='45 | 00055 | 9/30/2016 | Vodafone | Randy Singh | Newyork | Test Msg | TBL101 | PC | 1.00 | COMP101 | CS | 1.00'
SELECT * FROM dbo.SUBSTRING_INDEX (#s,'|',7)
This will gives two column output
45 | 00055 | 9/30/2016 | Vodafone | Randy Singh | Newyork | Test Msg TBL101 | PC | 1.00 | COMP101 | CS | 1.00
Finally got a solution almost identical to #JaydipJ. I thought to implement in a different way but the following should do using While loop:
DECLARE #str VARCHAR(1000),
#str1 VARCHAR(1000),
#str2 VARCHAR(1000),
#pos INT,
#counter INT
SET #str = '45 | 00055 | 9/30/2016 | Vodafone | Randy Singh | Newyork | Test Msg | TBL101 | PC | 1.00 | COMP101 | CS | 1.00.............. etc'
SET #counter = 0
SET #pos = 0
WHILE #counter < 7
BEGIN
SET #pos = CHARINDEX('|', #str, #pos + 1) ---- Gets the position of delimiter '|'
SET #counter = #counter + 1 ---- Increments the counter on the given counter value
END
SET #str1 = SUBSTRING(#str, 1, #pos) ---- Splits the string on the 7th position of delimiter '|'
SET #str2 = SUBSTRING(#str, #pos + 1, LEN(#str) - #pos) ---- Splits the rest of the string
Print 'str1='+ #str1
Print 'str2='+ #str2
SELECT #str1 AS String1, #str2 AS String2
The While loop is used to iterate through the string and getting the Delimiter position, it splits the string.
example Code
Declare
#table1 VARCHAR(MAX)
Set #table1 = 'Select * from #tempTbl'
Declare
#List VARCHAR(MAX),
#Pivot VARCHAR(MAX)
Select #List = ISNULL(#List + ',', '') + TrxCd From TransacMaster Where Module = 'CB'
Set #Pivot = '
SELECT ROW_NUMBER() OVER (ORDER BY DebtorCd ASC) As RowIndex, *
FROM (
Select Distinct
c.UserId,
d.Name,
b.TrxCd
SUM(b.Amount) As Amount
From tbl_InvH a
Inner Join tbl_InvD b on a.subCd = b.subCd and a.InvNo = b.InvNo
Left Join tbl_User c On a.UserId = c.UserId
Left Join tbl_Personnel d on c.PersonnelId = d.PersonnelId
Group By c.UserId, d.Name, b.TrxCd
) as s
PIVOT
(
SUM(Amount)
FOR TrxCd IN (' + #List + ')
)AS pvt'
Declare #Result nVarchar(MAX)
Set #Result = #table1 + '
Union All
' + #Pivot
Exec sp_executesql #Result
I want to Convert Field Amount from decimal to String, because after this I want to UNION with another tables, but field amount and field from another table is different type.
I have tried CAST(SUM(Amount) as Varchar) But Error :
'CAST' is not a recognized aggregate function.
I can't Convert on Main Select because Field of TrxCd is Dynamic
Result Of Pivot
RowIndex | UserId | Name | IT01 | IT02 | IT03 | IT04
--------------------------------------------------------------------------------
1 | John | John Ivy | 2,000 | 2,000 | 1,000 | 5,000
2 | Merry | Merry Ish | 1,000 | 1,000 | 1,000 | 6,000
other Table
RowIndex | UserId | Name | Transac1 | Transac2 | Transac3 | Transac4
-------------------------------------------------------------------------------------------------
1 | John | John Ivy | Trx Bank A | Trx Bank B | Trx Bank C | Trx Bank D
What should I do to Convert Field Amount from Pivot.
Because of the dynamic nature, you could take the same #List expression Select #List = ISNULL(#List + ',', '') + TrxCd From TransacMaster Where Module = 'CB' and create a second for the dynamic casting in the main select;
Select #List2 = ISNULL(#List2 + ',', '') + 'cast(' + TrxCd + 'as varchar)' From TransacMaster Where Module = 'CB'
Then use this and additional columns required to replace the asterix in the main select;
'SELECT ROW_NUMBER() OVER (ORDER BY DebtorCd ASC) As RowIndex, UserId, Name,' + #List2 +'....'