Get Cat1/Cat2/Cat3 string from self referencing table - sql-server

I am trying to yield a string that reads like Cat1/Cat2/Cat3, etc, from a self-referencing table.
Data looks like this:
CategoryTable
CategoryID, [Name], ParentID
1, Root, 0
2, Cat1, 1
3, Cat2, 2
4, Cat3, 3
5, Cat4, 1
6, Cat5, 5
I want to yield:
Root/Cat1/Cat2/Cat3
Root/Cat4/Cat5
How do I do this in sql server?

You can use CTE
SQL Fiddler
WITH cte AS (
SELECT CategoryID,CAST(Name AS VARCHAR(4000)) AS Name
FROM Category
WHERE ParentID = 0
UNION ALL
SELECT c.CategoryID, CAST(e.Name + '/' + c.Name AS VARCHAR(4000))
FROM cte e
INNER JOIN Category c
ON c.ParentID = e.CategoryID
)
SELECT c1.Name
FrOM cte c1
WHERE NOT EXISTS (SELECT 1 FROM cte c2 where c1.name <> c2.name AND c2.name like c1.NAME + '%')

try this :
DECLARE #str VARCHAR(255) --Or whatever length you need
SET #str = ''
SELECT #str = #str + [Name] + '/' FROM CategoryTable
SET #str = SUBSTRING(#str,0,LEN(#str)) -- remove the trailing '/'
PRINT #str

Related

SQL Server query CTE parent child, works in 2012 local but not in 2012 live, types don't match

This query works in one server version but not in another.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[EventDetails]
#EventID AS VARCHAR(20)
AS
BEGIN
WITH CTE(CategoryID, FullCategName, OrderString) AS
(
SELECT
CategoryID,
CAST(CategoryName AS VARCHAR(MAX)),
CAST(CAST(CategoryID AS CHAR(5)) AS VARCHAR(MAX)) OrderString
FROM
CategoryTbl
WHERE
ParentCategoryIDf is NULL
UNION ALL
SELECT
p.CategoryID,
CAST(c.FullCategName + ' >> ' + p.CategoryName AS VARCHAR(MAX)),
CAST(c.OrderString + CAST(p.CategoryID AS CHAR(5)) AS VARCHAR(MAX)) OrderString
FROM
CategoryTbl p
JOIN
CTE c ON c.CategoryID = p.ParentCategoryIDf
)
SELECT
(SELECT TOP 1 i.ImageUrl
FROM ImageTbl i
WHERE i.ProductIDf = p.EventID) AS ImageURL, *
FROM
EventTbl p
LEFT JOIN
CTE c on c.CategoryID = p.CategoryIDf
WHERE
p.EventID = #EventID
END
This is probably a collation issue, try this:
WITH CTE(CategoryID, FullCategName, OrderString) AS (
SELECT
CategoryID
, cast(CategoryName as varchar(max)) Collate SQL_Latin1_General_CP1_CI_AS as FullCategName
, cast(cast(CategoryID as char(5)) as varchar(max)) Collate SQL_Latin1_General_CP1_CI_AS as OrderString
FROM CategoryTbl
WHERE ParentCategoryIDf is NULL
UNION ALL
SELECT
p.CategoryID
, cast(c.FullCategName + ' >> ' + p.CategoryName as varchar(max)) Collate SQL_Latin1_General_CP1_CI_AS
, cast(c.OrderString + cast(p.CategoryID as char(5)) as varchar(max)) Collate SQL_Latin1_General_CP1_CI_AS --OrderString
FROM CategoryTbl p
JOIN CTE c
ON c.CategoryID = p.ParentCategoryIDf
)
select
(select top 1 i.ImageUrl
from ImageTbl i
where i.ProductIDf=p.EventID) as ImageURL
, *
from EventTbl p
left join CTE c on c.CategoryID=p.CategoryIDf
where p.EventID=#EventID
end
Reference:
T-SQL CTE Error: Types don't match between the anchor and the recursive part

How to concatenate multiple rows into one based on id in sql server

Actually i have three columns. ID, MedID, Name. With my query i am getting a result look like the below.
ID MedID Name
1 101 TestData1
1 124 TestData2
Query
select
cmd.ID, mm.MedID,mm.Name as Name
from
tbl1 mm
inner join
tbl2 cmd on cmd.medID= mm.MedID
where
cmd.ID= 1
Actually i am expecting a result like the below
ID MedID Name
1 101,124 TestData1,TestData2
So, how can get a result like this, Where i need to do changes in my query?
Any help appreciated. Thanks in advance !!!
Use STUFF and FOR XML PATH like this:
select id,
stuff((
select ',' + cast(MedId as varchar(30))
from t t1
where t1.id = t.id
order by MedID
for xml path('')
), 1, 1, '') MedID,
stuff((
select ',' + Name
from t t1
where t1.id = t.id
order by MedID
for xml path('')
), 1, 1, '') Name
from t
group by id;
Demo
DECLARE #TABLE TABLE (ID int, MedID varchar(10), Name varchar(10))
INSERT INTO #TABLE VALUES
(1, '101' , 'TestData1'),
(1, '124' , 'TestData2')
SELECT t.ID
, STUFF(( SELECT ', ' + MedID
FROM #TABLE
WHERE ID = t.ID
FOR XML PATH(''),TYPE)
.value('.','NVARCHAR(MAX)'),1,2,'') AS MedID
, STUFF(( SELECT ', ' + Name
FROM #TABLE
WHERE ID = t.ID
FOR XML PATH(''),TYPE)
.value('.','NVARCHAR(MAX)'),1,2,'') AS Name
FROM #TABLE t
GROUP BY t.ID

Convert XML output to varchar

I have this query
select
',' + CONVERT(VARCHAR,FileID)
from
[RETRY_INPUT_JSON] A
inner join
RETRY_JSON_STATUS B on JsonStatus = StatusID
where
RetryStatus = 'FAILED'
Union
select
',' + CONVERT(VARCHAR,FileID)
from
[RETRY_INPUT_JSON] A
inner join
RETRY_JSON_STATUS B on SendESBStatus = StatusID
where
RetryStatus In ('FAILED', 'Success')
order by
',' + CONVERT(VARCHAR,FileID)
FOR XML PATH('')
This returns this output:
I want to convert it to varchar.
For that I tried :
DECLARE #FILEID AS VARCHAR(MAX)
SET #FILEID =(SELECT STUFF
(
(
select ',' + CONVERT(VARCHAR,FileID) from [RETRY_INPUT_JSON] A inner join RETRY_JSON_STATUS B
on JsonStatus=StatusID
where RetryStatus='FAILED'
Union
select ',' + CONVERT(VARCHAR,FileID) from [RETRY_INPUT_JSON] A inner join RETRY_JSON_STATUS B
on SendESBStatus=StatusID
where RetryStatus In ('FAILED','Success')
ORDER BY ',' + CONVERT(VARCHAR,FileID) FOR XML PATH('')
),
1, 1, ''
) )
print #FILEID
But I get an error :
Msg 1086, Level 15, State 1, Line 18
The FOR XML clause is invalid in views, inline functions, derived tables, and subqueries when they contain a set operator. To work around, wrap the SELECT containing a set operator using derived table syntax and apply FOR XML on top of it.
Check This.
DECLARE #FILEID AS VARCHAR(MAX)
DECLARE #xml_var XML
SET #xml_var = ( select ',' + CONVERT(VARCHAR,A)
from
(
select
CONVERT(VARCHAR,FileID) A
from
[RETRY_INPUT_JSON] A
inner join
RETRY_JSON_STATUS B on JsonStatus = StatusID
where
RetryStatus = 'FAILED'
Union
select
CONVERT(VARCHAR,FileID) A
from
[RETRY_INPUT_JSON] A
inner join
RETRY_JSON_STATUS B on SendESBStatus = StatusID
where
RetryStatus In ('FAILED', 'Success')
)A
order by A
FOR XML PATH('')
)
select #FILEID = CONVERT(VARCHAR(MAX), #xml_var)
SELECT #FILEID
pRINT #FILEID

Pivot with Group by on SQL

I'm create sql syntax which create pivot Group By Product based on Category
CREATE TABLE #Product ( Product varchar(10),Category varchar(10),Stock int)
INSERT INTO #Product Values ('Item A','CatA',10)
INSERT INTO #Product Values ('Item A','CatB',5)
INSERT INTO #Product Values ('Item B','CatA',3)
INSERT INTO #Product Values ('Item B','CatB',5)
INSERT INTO #Product Values ('Item B','CatC',7)
INSERT INTO #Product Values ('Item B','CatD',10)
SELECT *
FROM
(
SELECT Product,Category,Stock
FROM #Product A
) src
pivot
(
SUM(Stock)
for Category in ([CatA], [CatB], [CatC],[CatD])
) piv;
DROP TABLE #Product
Result of Query
Product CatA CatB CatC CatD
Item A 10 5 NULL NULL
Item B 3 5 7 10
Result trying to achieve is
Product Cat1 Stock1 Cat2 Stock2 Cat3 Stock3 Cat4 Stock4
Item A CatA 10 CatB 5 CatC 0 CatD 0
Item B CatA 3 CatB 5 CatC 7 CatD 10
Thanks for the help
You need to create all combinations of Product and Category first. Then do a LEFT JOIN on #Product to get the Stock. Finally, use the result to pivot the data.
Since I'm not familiar with the PIVOT command, I used another technique called Dynamic Crosstab
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql =
'SELECT
Product' + CHAR(10);
SELECT #sql = #sql +
STUFF((
SELECT
' ,MAX(CASE WHEN RN = ' + CONVERT(VARCHAR(3), t.RN) + ' THEN Category END) AS ' + QUOTENAME('Cat' + CONVERT(VARCHAR(3), t.RN)) + CHAR(10) +
' ,MAX(CASE WHEN RN = ' + CONVERT(VARCHAR(3), t.RN) + ' THEN Stock END) AS ' + QUOTENAME('Stock' + CONVERT(VARCHAR(3), t.RN)) + CHAR(10)
FROM (
SELECT DISTINCT
RN = ROW_NUMBER() OVER(PARTITION BY Product ORDER BY(SELECT NULL))
FROM #Product
) t
FOR XML PATH('')
), 1, 1, ' ');
SELECT #sql = #sql +
'FROM(
SELECT
p1.Product,
p1.Category,
Stock = ISNULL(p2.Stock, 0),
RN = ROW_NUMBER() OVER(PARTITION BY p1.Product ORDER BY p1.Category)
FROM (
SELECT
t1.Product, t2.Category
FROM (
SELECT DISTINCT Product FROM #Product
) t1
CROSS JOIN (
SELECT DISTINCT Category FROM #Product
) t2
) p1
LEFT JOIN #Product p2
ON p1.Product = p2.Product
AND p1.Category = p2.Category
)t
GROUP BY Product;';
PRINT #sql;
EXEC sp_executesql #sql;
ONLINE DEMO

How to split required text from SQL Server table columns

I used a query which splits the texts in a column in one table and retrieves the corresponding id's from another table.
Here is the query:
DECLARE #X XML
DECLARE #STR VARCHAR(MAX) = ''
SELECT #STR = #STR + ';' + P_AUTHOR
FROM sub_aminer_paper
WHERE PID = 4
ORDER BY PID
SELECT #STR = substring(#STR,2,len(#STR))
SELECT #X = CONVERT(xml,' <root> <s>' + REPLACE(#STR,';','</s> <s>') + '</s> </root> ')
SELECT aid as [Author_id], name as [Author_Name]
FROM sub_aminer_author s
INNER JOIN
(SELECT
row_number() OVER(ORDER BY (SELECT null)) AS rn,
T.c.value('.','varchar(max)') AS value
FROM
#X.nodes('/root/s') T(c) ) t ON t.value = s.name
ORDER BY rn
If column p_author contains this value i.e.
Sushil Jajodia;Peter A. Ng;Frederick N. Springsteel
Then this query gives following output i.e.
Author_id Author_Name
578328 Sushil Jajodia
865779 Peter A. Ng
669143 Frederick N. Springsteel
Now I want to have Author_id as skipping first author id e.g. I need output like this:
Author_id Author_Name
865779 Peter A. Ng
669143 Frederick N. Springsteel
Then also I have to insert these Author_id's in another table. Please help regarding this query.
Just add WHERE rn>1
DECLARE #X XML
DECLARE #STR VARCHAR(MAX)=''
SELECT #STR = #STR+';'+P_AUTHOR
FROM sub_aminer_paper
WHERE PID = 4
ORDER BY PID
SELECT #STR = substring(#STR,2,len(#STR))
SELECT #X = CONVERT(xml,' <root> <s>' + REPLACE(#STR,';','</s> <s>') + '</s> </root> ')
SELECT aid as [Author_id], name as [Author_Name]
FROM sub_aminer_author s
INNER JOIN (SELECT row_number()
OVER(ORDER BY (SELECT null)) AS rn, T.c.value('.','varchar(max)') AS value
FROM #X.nodes('/root/s') T(c)
) t ON t.value = s.name
WHERE rn>1
ORDER BY rn

Resources