T-SQL Recursive Query - Data Lineage - sql

Given the following table
I need to get "data lineage" of the database objects.
The expected output (something like that):
This is the script I've tried.
CREATE TABLE #smth
(
ParObj NVARCHAR(200)
,ChilObj NVARCHAR(200)
);
INSERT INTO #smth (
ParObj
,ChilObj
)
VALUES ( N'FactSales', N'qryFactSales' )
,( 'qryFactSales', 'qryFactSalesOnlineUnited' );
WITH cte
AS (
SELECT ParObj
,ChilObj
,level = 1
,path = CAST('root' AS VARCHAR(100))
FROM #smth
UNION ALL
SELECT t2.ParObj
,t2.ChilObj
,level = t1.level + 1
,Path = CAST(t1.path + ' ||| ' + CAST(t2.ChilObj AS VARCHAR(100)) AS VARCHAR(100))
FROM #smth AS t2
JOIN cte AS t1
ON t1.ChilObj = t2.ParObj
)
SELECT *
FROM cte
ORDER BY cte.path;
Is it even achievable somehow?

This version does what you want:
with cte as (
select parobj as obj, convert(nvarchar(max), NULL) as path
from smth
where not exists (select 1 from smth smth2 where smth2.chilobj = smth.parobj)
union all
select smth.chilobj as obj, convert(nvarchar(max), coalesce(path + ' -> ', '')) + cte.obj
from cte join
smth
on cte.obj = smth.parobj
)
select obj, coalesce(path + ' -> ' + obj, 'Root')
from cte;
Here is a db<>fiddle.

Related

SQL split string (all possible combination)

I would like to transform this string:
A1+A2+A3.B1+B2.C1
into
A1.B1.C1
A1.B2.C1
A2.B1.C1
A2.B2.C1
A3.B1.C1
A3.B2.C1
How can I do that? (note that each dimension(= a group separate by .), could have x values, I mean it can be A1+A2.B1.C1 or A1+A2.B1+B2+B3+B4+B5.C1+C2)
Thanks
If you have only 3 columns, then just use STRING_SPLIT: number your groups from first split and then do a join 3 times and select each group on corresponding join.
with a as (
select s2.value as v, dense_rank() over(order by s1.value) as rn
from STRING_SPLIT('A1+A2+A3.B1+B2.C1', '.') as s1
cross apply STRING_SPLIT(s1.value, '+') as s2
)
select
a1.v + '.' + a2.v + '.' + a3.v as val
from a as a1
cross join a as a2
cross join a as a3
where a1.rn = 1
and a2.rn = 2
and a3.rn = 3
| val |
----------
|A1.B1.C1|
|A2.B1.C1|
|A3.B1.C1|
|A1.B2.C1|
|A2.B2.C1|
|A3.B2.C1|
If you have indefinite number of groups, then it's better to use recursive CTE instead of dynamic SQL. What you should do:
Start with all the values from the first group.
On recursion step crossjoin all the values of the next group (i.e. step group number is current group number + 1).
Select the last recursion step where you'll have the result.
Code is below:
with a as (
select s2.value as v, dense_rank() over(order by s1.value) as rn
from STRING_SPLIT('A1+A2+A3.B1+B2+B3+B4.C1+C2.D1+D2+D3', '.') as s1
cross apply STRING_SPLIT(s1.value, '+') as s2
)
, b (val, lvl) as (
/*Recursion base*/
select cast(v as nvarchar(1000)) as val, rn as lvl
from a
where rn = 1
union all
/*Increase concatenation on each iteration*/
select cast(concat(b.val, '.', a.v) as nvarchar(1000)) as val, b.lvl + 1 as lvl
from b
join a
on b.lvl + 1 = a.rn /*Recursion step*/
)
select *
from b
where lvl = (select max(rn) from a) /*You need the last step*/
order by val
I won't add a tabular result since it is quite big. But try it by yourself.
Here is SQL server version and fiddle:
with lst(s) as (select * from STRING_SPLIT('A1+A2.B1+B2+B3+B4+B5.C1+C2','.'))
select t1+'.'+t2+'.'+t3 as res from
(select * from STRING_SPLIT((select s from lst where s like 'A%'), '+')) s1(t1) cross join
(select * from STRING_SPLIT((select s from lst where s like 'B%'), '+')) s2(t2) cross join
(select * from STRING_SPLIT((select s from lst where s like 'C%'), '+')) s3(t3);
Of course you can grow it in a regular fashion if the number of dimensions grows.
Here is a Postgresql solution:
with x(s) as (select string_to_array('A1+A2.B1+B2+B3+B4+B5.C1+C2','.'))
select t1||'.'||t2||'.'||t3 as res from
unnest((select string_to_array(s[1],'+') from x)) t1 cross join
unnest((select string_to_array(s[2],'+') from x)) t2 cross join
unnest((select string_to_array(s[3],'+') from x)) t3;
result:
res |
--------|
A1.B1.C1|
A1.B2.C1|
A1.B3.C1|
A1.B4.C1|
A1.B5.C1|
A2.B1.C1|
A2.B2.C1|
A2.B3.C1|
A2.B4.C1|
A2.B5.C1|
A1.B1.C2|
A1.B2.C2|
A1.B3.C2|
A1.B4.C2|
A1.B5.C2|
A2.B1.C2|
A2.B2.C2|
A2.B3.C2|
A2.B4.C2|
A2.B5.C2|
Here my code with your help. I didn't mention, but I can also have more or less than 3 parts, so I'm using a dynamic SQL for this:
declare #FILTER varchar(max)='B+C+D.A+G.T+Y+R.E'
-- Works also with A.B.C
-- Works also with A+B+C.D.E+F
-- Works also with A+B+C.D+E+F+G+H
declare #NB int
declare #SQL varchar(max)=''
select #NB=count(*) from STRING_SPLIT(#FILTER,'.')
set #SQL='
;with T(A,B) as
(select *, row_number() over (order by (select NULL))
from STRING_SPLIT(''' + #FILTER + ''',''.'')
)
select '
;with T(V,N) as (
select *, row_number() over (order by (select NULL))
from STRING_SPLIT(#FILTER,'.')
)
select #SQL=#SQL + 'T' + cast(N as varchar(max)) + ' + ''.'' + ' from T
set #SQL=left(#SQL,len(#SQL)-1) + ' as res from'
;with T(V,N) as (
select *, row_number() over (order by (select NULL))
from STRING_SPLIT(#FILTER,'.')
)
select #SQL=#SQL + '
(select * from STRING_SPLIT((select A from T where B=' + cast(N as varchar(max)) + '), ''+'')) s' + cast(N as varchar(max)) + '(t' + cast(N as varchar(max)) + ') cross join'
from T
set #SQL=left(#SQL,len(#SQL)-len('cross join'))
exec(#SQL)

Combine Multi Rows with COALESCE

Using SQL-Server 2012
I have the following Table:
Id Description
6192 Salzburg
6193 Salzburg
6194 Salzburg
6196 Innsbruck
6197 Innsbruck
6198 Innsbruck
6199 Innsbruck
6201 Bregenz
6202 Bregenz
6203 Bregenz
I want to Select each Distinct "Description" with all the Id's together in one string:
Description Ids
Salzburg '6192,6193,6194'
Innsbruck '6196,6197,6198'
I saw some similar code on this site [How to concatenate text from multiple rows into a single text string in SQL server?, but I couldn't figure it out yet for my purpose (don't want to use XML Path!). Here is what I have tried so far:
DECLARE #ids AS Nvarchar(MAX)
SELECT #ids = COALESCE(#ids + ',', '') + CAST(t.Id AS nvarchar(5))
FROM (SELECT tmp.Id FROM (SELECT id, [Description] FROM tblMasterPropValues WHERE IdCategory = 253 AND IsActive = 1) as tmp
WHERE [Description] = tmp.[Description]) AS t
SELECT #ids
--SELECT DISTINCT [Description], #ids AS IDs FROM tblMasterPropValues WHERE IdCategory = 253 AND IsActive = 1 AND Id IN (#ids)
I can't really get my head around it, and would appreciate any help on it.
You can try using STUFF() function
SELECT description, Ids = STUFF(
(SELECT ',' + Id
FROM tblMasterPropValues t1
WHERE t1.description = t2.description
FOR XML PATH (''))
, 1, 1, '') from tblMasterPropValues t2
group by description;
For that FOR XML PATH() is the right clause so, you can do :
SELECT DISTINCT v.description, STUFF(v1.ids, 1, 1, '''') + ''''
FROM tblMasterPropValues v CROSS APPLY
(SELECT ', '+ CAST(v1.Id AS VARCHAR(255))
FROM tblMasterPropValues v1
WHERE v1.description = v.description
FOR XML PATH('')
) v1(ids);
You can also make it by using recursive CTE
DECLARE #tblMasterPropValues TABLE (Id INT, Description VARCHAR(20))
INSERT INTO #tblMasterPropValues VALUES
(6192 , 'Salzburg'),
(6193 , 'Salzburg'),
(6194 , 'Salzburg'),
(6196 , 'Innsbruck'),
(6197 , 'Innsbruck'),
(6198 , 'Innsbruck'),
(6199 , 'Innsbruck'),
(6201 , 'Bregenz'),
(6202 , 'Bregenz'),
(6203 , 'Bregenz')
;WITH Tbl AS
(
SELECT
*,
ROW_NUMBER() OVER(PARTITION BY Description ORDER BY Id) AS RN,
COUNT(*) OVER(PARTITION BY Description) AS CNT
FROM #tblMasterPropValues
)
, Rcr AS (
SELECT *, CAST(Id AS varchar(max)) Ids
FROM Tbl WHERE RN = 1
UNION ALL
SELECT T.*, Rcr.Ids + ',' + CAST(T.Id AS VARCHAR(10)) Ids
FROM Rcr
INNER JOIN Tbl T ON T.RN = Rcr.RN + 1 and Rcr.Description = T.Description
)
SELECT RN, Description, Ids FROM Rcr
WHERE RN = CNT
Result:
Description Ids
-------------------- -----------------------
Salzburg 6192,6193,6194
Innsbruck 6196,6197,6198,6199
Bregenz 6201,6202,6203
Try this:
DECLARE #Table TABLE(ID INT, Description VARCHAR(25))
INSERT INTO #Table
VALUES (6192,'Salzburg' )
,(6193,'Salzburg' )
,(6194,'Salzburg' )
,(6196,'Innsbruck')
,(6197,'Innsbruck')
,(6198,'Innsbruck')
,(6199,'Innsbruck')
,(6201,'Bregenz' )
,(6202,'Bregenz' )
,(6203,'Bregenz' )
Query:
SELECT DISTINCT T2.Description,
SUBSTRING(
(
SELECT ','+CAST(T1.ID AS VARCHAR) AS [text()]
FROM #Table T1
WHERE T1.Description = T2.Description
ORDER BY T1.Description
FOR XML PATH ('')
), 2, 1000) [Ids]
FROM #Table T2
Result:
Description Ids
Bregenz 6201,6202,6203
Innsbruck 6196,6197,6198,6199
Salzburg 6192,6193,6194

Aggregate multiple rows into new single long row of data

I have a database with many rows of data per "case". Each "case" has a unique ID, but each row has a "multiple-choice-element" and a "value". Obviously there is a new row every time the user selects one of the multiple choice elements(mce) and the new value too. The unique ID is like a linchpin holding all of the rows together as a common element for this instance
The data is as follows:
UniqueID Value Text Username Contact
--------------------------------------------------
123456 No Sound Horn Johnson 0788
123456 Broken Headlight Johnson 0788
123456 Broken Windscreen Johnson 0788
I am looking to keep just one row of data, their user details, the key (unique ID), and then have multiple columns for each mce and each value.
UniqueID Username Contact Text Value Text Value Text Value
---------------------------------------------------------------------------------
123456 Johnson 0788 Horn No Sound Headlight Broken Windscreen Broken
I have done this using an update statement for each mce based on the Unique ID so far, but it's a bit clunky and long winded as a stored-procedure and can take quite a bit of time to run.
Can anyone suggest a better way please.
Thank you.
EDIT 2: I wasn't even sure this was possible, but I think I've found a way. Unfortunately, it's extremely hacky, and since you never posted your RDBMS tag, I don't even know if it will work for you.
I don't particularly like the solution, as I said - it feels clumsy to me, but it does work and I don't have any more time to dedicate to this issue. Unless someone else can figure out a way to make it work more efficiently, this is the best I can do for you. Note that I create and reference a temp table called #Numbers - you'll need this to stay in your query. Also note that you might end up with more columns than you want, but that will have to stay.
The following script will allow you to pivot two columns, preserving the relationship between a distinct value in column #1 (Txt) and multiple values in column #2 (Value)
CREATE TABLE #Data (UniqueID INT, Value varchar(10), Txt varchar(10), Username varchar(10), Contact INT)
INSERT INTO #Data (UniqueID, Value, Txt, Username, Contact)
SELECT 123456, 'No Sound', 'Horn', 'Johnson', 0788 UNION
SELECT 123456, 'Broken', 'Headlight', 'Johnson', 0788 UNION
SELECT 123456, 'Smashed', 'Headlight', 'Johnson', 0788 UNION
SELECT 123456, 'Shattered', 'Headlight', 'Johnson', 0788 UNION
SELECT 123456, 'Busted', 'Headlight', 'Johnson', 0788 UNION
SELECT 123456, 'Inop', 'Brake', 'Johnson', 0788
DECLARE #sql AS varchar(max)
DECLARE #vpivot_list AS varchar(max) -- Leave NULL for COALESCE technique
DECLARE #vselect_list AS varchar(max) -- Leave NULL for COALESCE technique
DECLARE #tpivot_list AS varchar(max) -- Leave NULL for COALESCE technique
DECLARE #tselect_list AS varchar(max) -- Leave NULL for COALESCE technique
CREATE TABLE #Numbers (Number INT)
;WITH NumberSequence( Number ) AS
(
SELECT 1 as Number
UNION ALL
SELECT Number + 1
FROM NumberSequence
WHERE Number < 100
)
INSERT INTO #Numbers (Number)
SELECT Number FROM NumberSequence
SELECT
#vpivot_list = COALESCE(#vpivot_list + ', ', '') + '[' + TxtValCombinations + ']'
FROM
(
SELECT
'T' + CAST(Txt.Number AS VARCHAR(5)) + '_' +
'V' + CAST(Val.Number AS VARCHAR(5)) AS TxtValCombinations
FROM
#Numbers Txt
INNER JOIN
(
SELECT MAX(CountTxt) MaxCountTxt
FROM
(
SELECT COUNT(DISTINCT Txt) CountTxt
FROM #Data
GROUP BY UniqueID
) cv
) MaxCountTxt ON
Txt.Number <= MaxCountTxt.MaxCountTxt
INNER JOIN
#Numbers Val ON
Val.Number <
(
SELECT MAX(CountValue) MaxCountValue
FROM
(
SELECT COUNT(Value) CountValue
FROM #Data
GROUP BY UniqueID, Txt
) cv
)
) PossibleValues
SELECT
#tpivot_list = COALESCE(#tpivot_list + ', ', '') + '[' + TxtCombinations + ']'
FROM
(
SELECT
'T' + CAST(Txt.Number AS VARCHAR(5)) AS TxtCombinations
FROM
#Numbers Txt
INNER JOIN
(
SELECT MAX(CountTxt) MaxCountTxt
FROM
(
SELECT COUNT(DISTINCT Txt) CountTxt
FROM #Data
GROUP BY UniqueID
) cv
) MaxCountTxt ON
Txt.Number <= MaxCountTxt.MaxCountTxt
) PossibleValues
SELECT #vselect_list = STUFF(
(
SELECT',' +
'T' + CAST(Txt.Number AS VARCHAR(5)) + '_' +
'V' + CAST(Val.Number AS VARCHAR(5)) --AS TxtValCombinations
FROM
#Numbers Txt
INNER JOIN
(
SELECT MAX(CountTxt) MaxCountTxt
FROM
(
SELECT COUNT(DISTINCT Txt) CountTxt
FROM #Data
GROUP BY UniqueID
) cv
) MaxCountTxt ON
Txt.Number <= MaxCountTxt.MaxCountTxt
INNER JOIN
#Numbers Val ON
Val.Number <
(
SELECT MAX(CountValue) MaxCountValue
FROM
(
SELECT COUNT(Value) CountValue
FROM #Data
GROUP BY UniqueID, Txt
) cv
)
ORDER BY Txt.Number, Val.Number
FOR XML PATH(''), type
).value('.', 'varchar(max)'), 1, 1, '')
SELECT #tselect_list = STUFF(
(
SELECT TxtValCombinations
FROM
(
SELECT',MAX(' +
'T' + CAST(Txt.Number AS VARCHAR(5)) + '_' +
'V' + CAST(Val.Number AS VARCHAR(5)) + ') AS '+
'T' + CAST(Txt.Number AS VARCHAR(5)) + '_' +
'V' + CAST(Val.Number AS VARCHAR(5)) AS TxtValCombinations
FROM
#Numbers Txt
INNER JOIN
(
SELECT MAX(CountTxt) MaxCountTxt
FROM
(
SELECT COUNT(DISTINCT Txt) CountTxt
FROM #Data
GROUP BY UniqueID
) cv
) MaxCountTxt ON
Txt.Number <= MaxCountTxt.MaxCountTxt
INNER JOIN
#Numbers Val ON
Val.Number <
(
SELECT MAX(CountValue) MaxCountValue
FROM
(
SELECT COUNT(Value) CountValue
FROM #Data
GROUP BY UniqueID, Txt
) cv
)
UNION ALL
SELECT',MAX(' +
'T' + CAST(Txt.Number AS VARCHAR(5)) +') AS T' + CAST(Txt.Number AS VARCHAR(5)) --AS TxtValCombinations
FROM
#Numbers Txt
INNER JOIN
(
SELECT MAX(CountTxt) MaxCountTxt
FROM
(
SELECT COUNT(DISTINCT Txt) CountTxt
FROM #Data
GROUP BY UniqueID
) cv
) MaxCountTxt ON
Txt.Number <= MaxCountTxt.MaxCountTxt
) s
ORDER BY TxtValCombinations
FOR XML PATH(''), type
).value('.', 'varchar(max)'), 1, 1, '')
SET #sql = '
SELECT UniqueID, Username, Contact, ' + #tselect_list + '
FROM
(
SELECT UniqueID, Username, Contact, Txt, tPIVOT_CODE, ' + #vselect_list + '
FROM
(
SELECT b.UniqueID, Value, Username, Contact, Txt, tPIVOT_CODE, vPIVOT_CODE
FROM
(
SELECT
Data.UniqueID,
Data.Username,
Data.Contact,
Data.Txt,
''T'' + CAST(grpTxt.TxtNum AS VARCHAR(5)) AS tPIVOT_CODE,
Data.Value,
''T'' + CAST(grpTxt.TxtNum AS VARCHAR(5)) + ''_V'' + CAST(ROW_NUMBER() OVER (PARTITION BY Data.UniqueID, Data.Txt ORDER BY Data.Value) AS VARCHAR(4)) vPIVOT_CODE
FROM
#Data Data
INNER JOIN
(
SELECT UniqueID, Txt, ROW_NUMBER() OVER (PARTITION BY UniqueID ORDER BY Txt) AS TxtNum
FROM #Data
GROUP BY UniqueID, Txt
) grpTxt ON
Data.UniqueID = grpTxt.UniqueID AND
Data.Txt = grpTxt.Txt
) b
) vp
PIVOT (
MIN(Value)
FOR vPIVOT_CODE IN (
' + #vpivot_list + '
)
) AS vpvt
) tp
PIVOT (
MIN(Txt)
FOR tPIVOT_CODE IN (
' + #tpivot_list + '
)
) AS tpvt
GROUP BY UniqueID, UserName, Contact
ORDER BY UniqueID, UserName, Contact
'
--PRINT #sql
--PRINT #tselect_list
--PRINT #vpivot_list
EXEC (#sql)
DROP TABLE #Data
DROP TABLE #Numbers

initialize and increment variable inside cte query sqlserver 2008

I am using sqlserver 2008 ,I want to initialize and increment variable (#NUMTwo) both at the same time, in my second part(Problem Line).
I am creating a cte query.
Is this possible , if yes then please let me know.
following is a sample example.I hope i am clear.
CREATE table #TempTable
(
childProductID INT,parentProductID INT,productModel varchar(50),[Num2] VARCHAR(100)
)
DECLARE #NUMTwo INT = 0
WITH tableR AS
(
-- First Part
SELECT childProductID = null,parentProductID=null,productModel from Products where productid in (#a),[Num2] = convert(varchar(100), '')
UNION ALL
--Second Part
SELECT e.childProductID,e.parentProductID,prd.productModel FROM ProductIncludes AS e
,[Num2] = convert(varchar(100),'1.' + #NUMTwo+=1 ) -- Problem line
INNER JOIN Products AS PRD ON e.childProductID = PRD.productID
WHERE parentProductID in (#a)
)
INSERT INTO #TempTable(childProductID,parentProductID,productModel,[Num2])
SELECT childProductID,parentProductID,productModel,[Num2]
END
SELECT * FROM #TempTable
You need to "Initialize" a column in the acnhor part of the query, and then "oncrement" this column in the recursive parts.
Something like
DECLARE #NUMTwo INT = 0
;WITH Test AS (
SELECT [Num2] = convert(varchar(MAX), ''),
#NUMTwo [N]
UNION ALL
SELECT [Num2] = '1.' + convert(varchar(MAX),[N]+1),
[N]+1
FROM TEst
WHERE [N] < 10
)
SELECT *
FROM Test
SQL Fiddle DEMO
If the parameter #NUMTwo is just for numbering rows you can use the ROW_NUMBER() OVER(...) instead of it like so:
WITH tableR AS
(
SELECT childProductID = NULL, parentProductID = NULL,
productModel, NUMTwo = CAST('0' AS VARCHAR(10))
FROM Products
WHERE
productid in (#a),
[Num2] = convert(varchar(100), '')
UNION ALL
SELECT e.childProductID, e.parentProductID,
prd.productModel,
NUMTwo = '1.' +
CAST( ROW_NUMBER() OVER(ORDER BY (SELECT 0)) AS VARCHAR(10))
FROM ProductIncludes AS e
INNER JOIN Products AS PRD ON e.childProductID = PRD.productID
WHERE parentProductID in (#a)
)

CTE error: "Types don't match between the anchor and the recursive part"

I am executing the following statement:
;WITH cte AS (
SELECT
1 as rn,
'name1' as nm
UNION ALL
SELECT
rn + 1,
nm = 'name' + CAST((rn + 1) as varchar(255))
FROM cte a WHERE rn < 10)
SELECT *
FROM cte
...which finishes with the error...
Msg 240, Level 16, State 1, Line 2
Types don't match between the anchor and the recursive part in column "nm" of recursive query "cte".
Where am I making the mistake?
Exactly what it says:
'name1' has a different data type to 'name' + CAST((rn+1) as varchar(255))
Try this (untested)
;with cte as
(
select 1 as rn, CAST('name1' as varchar(259)) as nm
union all
select rn+1,nm = 'name' + CAST((rn+1) as varchar(255))
from cte a where rn<10)
select * from cte
Basically, you have to ensure the length matches too. For the recursive bit, you may have to use CAST('name' AS varchar(4)) if it fails again
You need to cast both nm fields
;with cte as
(
select 1 as rn,
CAST('name1' AS VARCHAR(255)) as nm
union all
select rn+1,
nm = CAST('name' + CAST((rn+1) as varchar(255)) AS VARCHAR(255))
from cte a where rn<10)
select * from cte
For me problem was in different collation.
Only this helped me:
;WITH cte AS (
SELECT
1 AS rn,
CAST('name1' AS NVARCHAR(4000)) COLLATE DATABASE_DEFAULT AS nm
UNION ALL
SELECT
rn + 1,
nm = CAST('name' + CAST((rn + 1) AS NVARCHAR(255)) AS NVARCHAR(4000)) COLLATE DATABASE_DEFAULT
FROM cte a WHERE rn < 10)
SELECT *
FROM cte;
Hope it can help someone else.
;with cte as
(
select 1 as rn, 'name' + CAST(1 as varchar(255)) as nm
union all
select rn+1,nm = 'name' + CAST((rn+1) as varchar(255))
from cte a where rn<10)
select * from cte
In my case, I messed up the sequence of columns in top and bottom clauses of UNION ALL. And it turned out that a varchar column appeared 'under' an int one. An easy mistake to make of you have lots of columns
If you use CONCAT in the recursive term of a rcte, since the output type of concat is varchar(MAX), you only need to cast the column in the initial query:
WITH rcte AS (
SELECT 1 AS nr, CAST('1' AS varchar(MAX)) AS trail
UNION ALL
SELECT nr+1, CONCAT(trail, '/', nr+1)
FROM rcte
WHERE nr < 5
)
SELECT * FROM rcte;
I would recommend using nvarchar(max)
WITH CTE AS (
SELECT x,x_name FROM (VALUES (1,CAST('' AS nvarchar(MAX)))) AS test(x,x_name)
UNION ALL
SELECT x + 1 x, CONCAT(x_name,x+1) FROM CTE WHERE x < 10 )
SELECT * FROM CTE
WITH rcte AS (
SELECT 1 AS nr, CAST('1' AS varchar(MAX)) AS trail
UNION ALL
SELECT nr+1, cast(CONCAT(trail, '/', nr+1) as varchar(max))
FROM rcte
WHERE nr < 5
)
SELECT * FROM rcte;
;with tmp1(NewsId,DataItem ,HeaderText)
as
(
select NewsId, LEFT(HeaderText, CHARINDEX(',',HeaderText+',')-1),
STUFF(HeaderText, 1, CHARINDEX(',',HeaderText+','), '')
from Currentnews
union all
select NewsId, LEFT(HeaderText, CHARINDEX(',',HeaderText+',')-1),
STUFF(HeaderText, 1, CHARINDEX(',',HeaderText+','), '')
from tmp1
where HeaderText > ''
)
select NewsId, DataItem
from tmp1
order by NewsId