SQL multiple replace - sql

I want to read the company table and take out all possible suffixes from the name. Here's what I have so far:
declare #badStrings table (item varchar(50))
INSERT INTO #badStrings(item)
SELECT 'company' UNION ALL
SELECT 'co.' UNION ALL
SELECT 'incorporated' UNION ALL
SELECT 'inc.' UNION ALL
SELECT 'llc' UNION ALL
SELECT 'llp' UNION ALL
SELECT 'ltd'
select id, (companyname = Replace(name, item, '') FROM #badStrings)
from companies
where name != ''

Ed Northridge's answer will work, and I have upvoted it, but just in case multiple replacements are required I am adding another option using his sample data. If, for example one of the companies was called "The PC Company LTD" This would duplicate rows in the output with one being "The PC LTD" and the other "The PC Company". To resolve this there are 2 option depending on your desired outcome. The first is to only replace the "Bad Strings" when they occur at the end of the name.
SELECT c.ID, RTRIM(x.Name) [Name]
FROM #companies c
OUTER APPLY
( SELECT REPLACE(c.name, item, '') AS [Name]
FROM #badStrings
-- WHERE CLAUSE ADDED HERE
WHERE CHARINDEX(item, c.Name) = 1 + LEN(c.Name) - LEN(Item)
) x
WHERE c.name != ''
AND x.[Name] != c.Name
This would yield "The PC Company" with no duplicates.
The other option is replace All occurances of the Bad Strings recursively:
;WITH CTE AS
( SELECT c.ID, c.Name [OriginalName], RTRIM(x.Name) [Name], 1 [Level]
FROM #companies c
OUTER APPLY
( SELECT REPLACE(c.name, item, '') AS [Name]
FROM #badStrings
WHERE CHARINDEX(item, c.Name) = 1 + LEN(c.Name) - LEN(Item)
) x
WHERE c.name != ''
AND RTRIM(x.Name) != c.Name
UNION ALL
SELECT c.ID, OriginalName, RTRIM(x.Name) [Name], Level + 1 [Level]
FROM CTE c
OUTER APPLY
( SELECT REPLACE(c.name, item, '') AS [Name]
FROM #badStrings
WHERE CHARINDEX(item, c.Name) = 1 + LEN(c.Name) - LEN(Item)
) x
WHERE c.name != ''
AND x.[Name] != c.Name
)
SELECT DISTINCT ID, Name, OriginalName
FROM ( SELECT *, MAX(Level) OVER(PARTITION BY ID) [MaxLevel]
FROM CTE
) c
WHERE Level = maxLevel
This would yield "The PC" from "The PC Company".

The error I got running the snippet was:
Msg 102, Level 15, State 1, Line 12
Incorrect syntax near '='.
The below code isn't an ideal solution - it will only return a list of companies where their name has been changed by the REPLACE function.
declare #companies table (id int, name nvarchar(50))
INSERT INTO #companies(id, name)
SELECT 1,'One Company' UNION ALL
SELECT 2, 'Two co.' UNION ALL
SELECT 3, 'Three incorporated' UNION ALL
SELECT 4, 'Four inc.' UNION ALL
SELECT 5, 'Five llc' UNION ALL
SELECT 6, 'Six llp' UNION ALL
SELECT 7, 'Seven ltd'
select * from #companies
declare #badStrings table (item varchar(50))
INSERT INTO #badStrings(item)
SELECT 'company' UNION ALL
SELECT 'co.' UNION ALL
SELECT 'incorporated' UNION ALL
SELECT 'inc.' UNION ALL
SELECT 'llc' UNION ALL
SELECT 'llp' UNION ALL
SELECT 'ltd'
select * from #badStrings
Here is the edited query:
select id, x.Name
from #companies c
OUTER APPLY (
SELECT Replace(c.name, item, '') AS [Name]
FROM #badStrings
) x
where c.name != ''
AND x.[Name] != c.Name
This returns:
id Name
----------- --------
1 One
2 Two
3 Three
4 Four
5 Five
6 Six
7 Seven
(7 row(s) affected)
Hopefully it's useful
Edit:
An alternative to apply the match to those company names which end with the #badStrings value
select id, x.Name
from #companies c
OUTER APPLY (
SELECT Replace(c.name, item, '') AS [Name]
FROM #badStrings
WHERE c.Name LIKE '%'+item
) x
where c.name != ''

Related

Total sum wrong value in Dynamic Pivot

I have complicated query which works pretty good (MS SQL 2012). But it makes a mistake when sum up same price items. It count them correctly but only takes price once instead of taking them as a count number. It only appears when same item has same price and from same country. Here is my query ;
CREATE TABLE #ITEMS(ID INT,NAME VARCHAR(30))
INSERT INTO #ITEMS
SELECT 1, 'laptop'
UNION ALL
SELECT 2, 'phone'
UNION ALL
SELECT 3, 'playstation'
UNION ALL
SELECT 4, 'MacBook'
CREATE TABLE #Country(ID INT,NAME VARCHAR(30))
INSERT INTO #Country
SELECT 1, 'England'
UNION ALL
SELECT 2, 'Sweden'
UNION ALL
SELECT 3, 'Russia'
UNION ALL
SELECT 4, 'Italy'
CREATE TABLE [#Pre-Request](Id INT, countryId INT, ItemId INT)
INSERT INTO [#Pre-Request]
SELECT 1,1,3
UNION ALL
SELECT 2,2,1
UNION ALL
SELECT 3,2,2
UNION ALL
SELECT 4,3,3
UNION ALL
SELECT 5,3,3
UNION ALL
SELECT 6,2,3
CREATE TABLE #Offers(Id INT, PRICE VARCHAR(50))
INSERT INTO #Offers
SELECT 18,'257$'
UNION ALL
SELECT 19,'151$'
UNION ALL
SELECT 20,'424$'
UNION ALL
SELECT 21,'433$'
UNION ALL
SELECT 22,'151$'
CREATE TABLE #Request(Id INT, preReqId INT, requestStatus INT,winOfferId INT)
INSERT INTO #Request
SELECT 44, 1, 3, 18
UNION ALL
SELECT 11, 2, 4, 21
UNION ALL
SELECT 53, 3, 4, 20
UNION ALL
SELECT 87, 4, 3, 22
UNION ALL
SELECT 43, 5, 3, 19
UNION ALL
SELECT 43, 6, 2, Null
;WITH CTE AS
(
SELECT DISTINCT I.NAME ITEMNAME,C.NAME COUNTRYNAME
,CAST(REPLACE(TAB.PRICE,'$','')AS INT)PRICE
,COUNT(CASE WHEN TAB.PRICE IS NOT NULL THEN I.NAME END) OVER(PARTITION BY C.NAME,I.NAME) CNTITEM
FROM [#Pre-Request] PR
LEFT JOIN #Items I ON PR.ITEMID=I.ID
LEFT JOIN #COUNTRY C ON PR.COUNTRYID = C.ID
OUTER APPLY
(
SELECT R.preReqId,R.winOfferId,O.PRICE
FROM #Request R
JOIN #Offers O ON R.winOfferId=O.Id
WHERE PR.ID=R.preReqId
)TAB
UNION
-- Used to select Item name and country that are not in Pre-request table and other tables
SELECT I.NAME ,C.NAME ,NULL,0
FROM #Items I
CROSS JOIN #COUNTRY C
)
,CTE2 AS
(
-- Find the sum for number of items
SELECT DISTINCT ISNULL(ITEMNAME,'TOTAL')ITEMNAME,ISNULL(COUNTRYNAME,'TOTAL')COUNTRYNAME,
SUM(PRICE)PRICE
FROM CTE
GROUP BY ITEMNAME,COUNTRYNAME
WITH CUBE
)
,CTE3 AS
(
-- Find the sum of PRICE
SELECT DISTINCT ISNULL(ITEMNAME,'TOTAL')ITEMNAME,ISNULL(COUNTRYNAME,'TOTAL')COUNTRYNAME--,CNTITEM
,SUM(CNTITEM)CNTITEM
FROM
(
SELECT DISTINCT ITEMNAME,COUNTRYNAME,CNTITEM
FROM CTE
)TAB
GROUP BY ITEMNAME,COUNTRYNAME
WITH CUBE
)
SELECT C2.*,C3.CNTITEM,
CAST(C3.CNTITEM AS VARCHAR(20))+'x'+' ' + CAST(C2.PRICE AS VARCHAR(20))+'$' NEWCOL
INTO #NEWTABLE
FROM CTE2 C2
JOIN CTE3 C3 ON C2.COUNTRYNAME=C3.COUNTRYNAME AND C2.ITEMNAME=C3.ITEMNAME
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + ITEMNAME + ']', '[' + ITEMNAME + ']')
FROM (SELECT DISTINCT ITEMNAME FROM #NEWTABLE WHERE ITEMNAME<>'TOTAL') PV
ORDER BY ITEMNAME
-- Since we need Total in last column, we append it at last
SELECT #cols += ',[Total]'
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT COUNTRYNAME,' + #cols + ' FROM
(
SELECT DISTINCT ITEMNAME,COUNTRYNAME,ISNULL(NEWCOL,''0x 0$'')NEWCOL
FROM #NEWTABLE
) x
PIVOT
(
MIN(NEWCOL)
FOR ITEMNAME IN (' + #cols + ')
) p
ORDER BY CASE WHEN (COUNTRYNAME=''Total'') THEN 1 ELSE 0 END,COUNTRYNAME'
EXEC SP_EXECUTESQL #query
and here is result ;
As you can see there are 2 "playstation" from "Russia" it takes correct count (2x) but only take 1 price "151$" (normally it must be 302$). How can I fix this without making major changes from query? Thank you.
I think this does what you want. The problem is in your first CTE where you do the item count and get a distinct on the ItemName, CountryName, and Price.
Instead of getting a distinct, do a group by as shown below and SUM the price.
SELECT I.NAME ITEMNAME, C.NAME COUNTRYNAME
,SUM(CAST(REPLACE(TAB.PRICE,'$','')AS INT))PRICE
,COUNT(CASE WHEN TAB.PRICE IS NOT NULL THEN 1 ELSE NULL END) CNTITEM
FROM [#Pre-Request] PR
LEFT JOIN #Items I ON PR.ITEMID=I.ID
LEFT JOIN #COUNTRY C ON PR.COUNTRYID = C.ID
OUTER APPLY
(
SELECT R.preReqId,R.winOfferId,O.PRICE
FROM #Request R
JOIN #Offers O ON R.winOfferId=O.Id
WHERE PR.ID=R.preReqId
)TAB
GROUP BY
I.NAME
,C.NAME
EDIT:
Here are the results I get:
Here's all of your code starting from the CTEs:
;WITH CTE AS
(
SELECT I.NAME ITEMNAME, C.NAME COUNTRYNAME
,SUM(CAST(REPLACE(TAB.PRICE,'$','')AS INT))PRICE
,COUNT(CASE WHEN TAB.PRICE IS NOT NULL THEN 1 ELSE NULL END) CNTITEM
FROM [#Pre-Request] PR
LEFT JOIN #Items I ON PR.ITEMID=I.ID
LEFT JOIN #COUNTRY C ON PR.COUNTRYID = C.ID
OUTER APPLY
(
SELECT R.preReqId,R.winOfferId,O.PRICE
FROM #Request R
JOIN #Offers O ON R.winOfferId=O.Id
WHERE PR.ID=R.preReqId
)TAB
GROUP BY
I.NAME
,C.NAME
UNION
-- Used to select Item name and country that are not in Pre-request table and other tables
SELECT I.NAME ,C.NAME ,NULL,0
FROM #Items I
CROSS JOIN #COUNTRY C
)
,CTE2 AS
(
-- Find the sum for number of items
SELECT DISTINCT ISNULL(ITEMNAME,'TOTAL')ITEMNAME,ISNULL(COUNTRYNAME,'TOTAL')COUNTRYNAME,
SUM(PRICE)PRICE
FROM CTE
GROUP BY ITEMNAME,COUNTRYNAME
WITH CUBE
)
,CTE3 AS
(
-- Find the sum of PRICE
SELECT DISTINCT ISNULL(ITEMNAME,'TOTAL')ITEMNAME,ISNULL(COUNTRYNAME,'TOTAL')COUNTRYNAME--,CNTITEM
,SUM(CNTITEM)CNTITEM
FROM
(
SELECT DISTINCT ITEMNAME,COUNTRYNAME,CNTITEM
FROM CTE
)TAB
GROUP BY ITEMNAME,COUNTRYNAME
WITH CUBE
)
SELECT C2.*,C3.CNTITEM,
CAST(C3.CNTITEM AS VARCHAR(20))+'x'+' ' + CAST(C2.PRICE AS VARCHAR(20))+'$' NEWCOL
INTO #NEWTABLE
FROM CTE2 C2
JOIN CTE3 C3 ON C2.COUNTRYNAME=C3.COUNTRYNAME AND C2.ITEMNAME=C3.ITEMNAME
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + ITEMNAME + ']', '[' + ITEMNAME + ']')
FROM (SELECT DISTINCT ITEMNAME FROM #NEWTABLE WHERE ITEMNAME<>'TOTAL') PV
ORDER BY ITEMNAME
-- Since we need Total in last column, we append it at last
SELECT #cols += ',[Total]'
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT COUNTRYNAME,' + #cols + ' FROM
(
SELECT DISTINCT ITEMNAME,COUNTRYNAME,ISNULL(NEWCOL,''0x 0$'')NEWCOL
FROM #NEWTABLE
) x
PIVOT
(
MIN(NEWCOL)
FOR ITEMNAME IN (' + #cols + ')
) p
ORDER BY CASE WHEN (COUNTRYNAME=''Total'') THEN 1 ELSE 0 END,COUNTRYNAME'
EXEC SP_EXECUTESQL #query

Print result by merging records in a table

I have a table with name "PrintWord" and column name as col_letter and data in it is as follows:
"col_letter"
S
A
C
H
I
N
I would like to print the o/p from this table as:
SACHIN
Thanks!
DECLARE #t table
(
Name varchar(10)
)
INSERT INTO #t
SELECT 's' UNION ALL
SELECT 'a' UNION ALL
SELECT 'c' UNION ALL
SELECT 'h' UNION ALL
SELECT 'i' UNION ALL
SELECT 'n'
SELECT DISTINCT
stuff(
(
SELECT ' '+ [Name] FROM #t FOR XML PATH('')
),1,1,'')
FROM (SELECT DISTINCT Name FROM #t ) t
There is a hard-coded version :
SELECT col_letter
FROM PrintWord
ORDER BY
CASE col_letter
WHEN 'S' THEN 1
WHEN 'A' THEN 2
WHEN 'C' THEN 3
WHEN 'H' THEN 4
WHEN 'I' THEN 5
WHEN 'N' THEN 6
END
FOR XML PATH('')
You need an ORDER BY clause to guarantee the order of the letters.

Replace multiple characters in SQL

I have a problem where I want to replace characters
I am using replace function but that is not giving desired output.
Values of column table_value needs to replaced with their fill names like
E - Email
P - Phone
M - Meeting
I am using this query
select table_value,
replace(replace(replace(table_value, 'M', 'MEETING'), 'E', 'EMAIL'), 'P', 'PHONE') required_value
from foobar
so second required_value row should be EMAIL,PHONE,MEETING and so on.
What should I do so that required value is correct?
The below will work (even it's not a smart solution).
select
table_value,
replace(replace(replace(replace(table_value, 'M', 'MXXTING'), 'E', 'XMAIL'), 'P', 'PHONX'), 'X', 'E') required_value
from foobar
You can do it using CTE to split the table values into E, P and M, then replace and put back together.
I assumed each record has a unique identifer Id but please replace that with whatever you have.
;WITH cte
AS
(
SELECT Id, SUBSTRING(table_value, 1, 1) AS SingleValue, 1 AS ValueIndex
FROM replacetable
UNION ALL
SELECT replacetable.Id, SUBSTRING(replacetable.table_value, cte.ValueIndex + 1, 1) AS SingleValue, cte.ValueIndex + 1 AS ValueIndex
FROM cte
INNER JOIN replacetable ON cte.ValueIndex < LEN(replacetable.table_value)
)
SELECT DISTINCT Id,
STUFF((SELECT DISTINCT ','+ CASE SingleValue
WHEN 'E' THEN 'EMAIL'
WHEN 'P' THEN 'PHONE'
WHEN 'M' THEN 'MEETING'
END
FROM cte c
WHERE c.Id = cte.Id
AND SingleValue <> ','
FOR XML PATH ('')),1,1,'')
FROM cte
Sorry , for mess code, maybe this is not best way to solve this, but what I've tried:
SET QUOTED_IDENTIFIER ON
SET ANSI_NULLS ON
GO
CREATE Function [dbo].[fn_CSVToTable]
(
#CSVList Varchar(max)
)
RETURNS #Table TABLE (ColumnData VARCHAR(100))
AS
BEGIN
DECLARE #S varchar(max),
#Split char(1),
#X xml
SELECT #Split = ','
SELECT #X = CONVERT(xml,' <root> <s>' + REPLACE(#CSVList,#Split,'</s> <s>') + '</s> </root> ')
INSERT INTO #Table
SELECT CASE RTRIM(LTRIM(T.c.value('.','varchar(20)'))) WHEN 'M' THEN 'Meeting'
WHEN 'P' THEN 'Phone'
WHEN 'E' THEN 'Email'
End
FROM #X.nodes('/root/s') T(c)
RETURN
END
GO
Then When I run this:
Select Main.table_value,
Left(Main.ColumnData,Len(Main.ColumnData)-1) As ColumnData
From
(
Select distinct tt2.table_value,
(
Select tt1.ColumnData+ ',' AS [text()]
From (
SELECT
*
FROM dbo.TestTable tt
CROSS APPLY dbo.fn_CSVToTable(tt.table_value)
) tt1
Where tt1.table_value = tt2.TABLE_value
ORDER BY tt1.table_value
For XML PATH ('')
) ColumnData
From dbo.TestTable tt2
) [Main]
I get this:
table_value ColumnData
-------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
E,P Email,Phone
E,P,M Email,Phone,Meeting
P,E Phone,Email
P,M Phone,Meeting
(4 row(s) affected)
You could also use a DECODE or CASE to translate the values.

recursive query with peer relations

Let's say there is a table of relationships
(entity_id, relationship, related_id)
1, A, 2
1, A, 3
3, B, 5
1, C, null
12, C, 1
100, C, null
I need a query that will pull all related rows.
For example, if i queried for entity_id = 1, the following rows should be pulled
1, A, 2
1, A, 3
3, B, 5
1, C, null
12, C, 1
Actually, if i queried for entity_id = 1, 2, 3, 5, or 12, the resultset should be the same.
This is different than the standard manager-employee paradigm as there is no hierarchy. The relationships can go in any direction.
EDIT
None of the answers posted thus far worked.
I was able to come up with a solution that works.
I'll give the solution credit to the one who can clean this monstrosity into something more elegant.
with tab as (
-- union for reversals
select id, entity_id, r.related_id, 1 level
, cast('/' + cast(entity_id as varchar(1000)) + '/' as varchar(1000)) path
from _entity_relation r
where not exists(select null from _entity_relation r2 where r2.related_id=r.entity_id)
or r.related_id is null
union
select id, related_id, r.entity_id, 1 level
, cast('/' + cast(related_id as varchar(1000)) + '/' as varchar(1000)) path
from _entity_relation r
where not exists(select null from _entity_relation r2 where r2.related_id=r.entity_id)
or r.related_id is null
-- create recursive path
union all
select r.id, r.entity_id, r.related_id, tab.level+1
, cast(tab.path + '/' + cast(r.entity_id as varchar(100)) + '/' + '/' + cast(r.related_id as varchar(1000)) + '/' as varchar(1000)) path
from _entity_relation r
join tab
on tab.related_id = r.entity_id
)
select x.id
, x.entity_id
,pr.description as relation_description
,pt.first_name + coalesce(' ' + pt.middle_name,'') + ' ' + pt.last_name as relation_name
,CONVERT(CHAR(10), pt.birth_date, 101) as relation_birth_date
from (
select entity_id, MAX(id) as id from (
select distinct tab.id, entity_id
from tab
join(
select path
from tab
where entity_id=#in_entity_id
) p on p.path like tab.path + '%' or tab.path like p.path + '%'
union
select distinct tab.id, related_id
from tab
join(
select path
from tab
where entity_id=#in_entity_id
) p on p.path like tab.path + '%' or tab.path like p.path + '%'
union
select distinct tab.id, entity_id
from tab
join(
select path
from tab
where related_id=#in_entity_id
) p on p.path like tab.path + '%' or tab.path like p.path + '%'
union
select distinct tab.id, related_id
from tab
join(
select path
from tab
where related_id=#in_entity_id
) p on p.path like tab.path + '%' or tab.path like p.path + '%'
) y
group by entity_id
) x
join _entity_relation pr on pr.id = x.id
join _entity pt on pt.id = x.entity_id
where x.entity_id <> #in_entity_id;
Please be careful with you data as to accomplish your task you must avoid circular references. The following query can be optimized but for sure it'll work
;with tab as (
select entity_id, relationship, related_id, 1 level, cast('/' + cast(entity_id as varchar(1000)) as varchar(1000)) path
from #r r
where not exists(select null from #r r2 where r2.related_id=r.entity_id)
or r.related_id is null
union all
select r.entity_id, r.relationship, r.related_id, tab.level+1, cast(tab.path + '/' + cast(r.entity_id as varchar(100)) as varchar(1000)) path
from #r r
join tab
on tab.related_id = r.entity_id
)
select distinct tab.*
from tab
join(
select path
from tab
where entity_id=1) p
on p.path like tab.path + '%' or tab.path like p.path + '%'
Solution using two CTEs
I first created a table with relationships that go both ways and then created a recursive CTE that uses this both ways results to build whole hierarchies with ancestor paths...
with both as
(
select *, 0 as rev
from t
where related_id is not null
union
select *, 1
from t
),
recurs as
(
select *, cast('/' as varchar(100)) as anc
from both
where entity_id is null
union all
select b.*, cast(re.anc + cast(b.entity_id as varchar) + '/' as varchar(100))
from both b
join recurs re
on (re.related_id = b.entity_id)
where charindex('/'+cast(isnull(b.entity_id,'') as varchar)+'/', re.anc) = 0
)
select *
/*
THIS ONE SHOULD BE USED TO RETURN TO ORIGINAL
case when is_reverse = 1 then related_id else entity_id end as entity_id,
relationship,
case when is_reverse = 0 then related_id else entity_id end as related_id
*/
from recurs
where related_id = xXx or
charindex('/'+cast(xXx as varchar)+'/', anc) != 0
Replace xXx with actual value.
This query assumes that root element is the one with entity_id = null, so it builds the whole recursion from there. If that's not the case you'll have to change it accordingly.
I've added loop checks either loops are 1,2,3,4,5,1 or 1,2,3,4,5,3... So total or partial loops. Both will work.

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