Grouping with partition and over in TSql - sql

I have a simple table
CREATE TABLE [dbo].[Tooling](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NOT NULL,
[Status] [int] NOT NULL,
[DateFinished] [datetime] NULL,
[Tooling] [nvarchar](50) NULL,
[Updated] [datetime] NULL,
) ON [PRIMARY]
with following values
SET IDENTITY_INSERT [dbo].[Tooling] ON
GO
INSERT [dbo].[Tooling] ([Id], [Name], [Status], [DateFinished], [Tooling], [Updated]) VALUES (1, N'Large', 0, NULL, NULL, CAST(N'2015-05-05 00:00:00.000' AS DateTime))
GO
INSERT [dbo].[Tooling] ([Id], [Name], [Status], [DateFinished], [Tooling], [Updated]) VALUES (2, N'Large', 1, NULL, N'1', CAST(N'2015-05-10 00:00:00.000' AS DateTime))
GO
INSERT [dbo].[Tooling] ([Id], [Name], [Status], [DateFinished], [Tooling], [Updated]) VALUES (3, N'Small', 0, NULL, N'2', CAST(N'2015-05-11 00:00:00.000' AS DateTime))
GO
INSERT [dbo].[Tooling] ([Id], [Name], [Status], [DateFinished], [Tooling], [Updated]) VALUES (4, N'Large', 2, NULL, N'1', CAST(N'2015-05-12 00:00:00.000' AS DateTime))
GO
INSERT [dbo].[Tooling] ([Id], [Name], [Status], [DateFinished], [Tooling], [Updated]) VALUES (5, N'Large', 2, NULL, N'2', CAST(N'2015-05-12 00:00:00.000' AS DateTime))
GO
INSERT [dbo].[Tooling] ([Id], [Name], [Status], [DateFinished], [Tooling], [Updated]) VALUES (6, N'Large', 1, NULL, N'1', CAST(N'2015-05-13 00:00:00.000' AS DateTime))
GO
INSERT [dbo].[Tooling] ([Id], [Name], [Status], [DateFinished], [Tooling], [Updated]) VALUES (7, N'Large', 1, NULL, N'2', CAST(N'2015-05-14 00:00:00.000' AS DateTime))
GO
INSERT [dbo].[Tooling] ([Id], [Name], [Status], [DateFinished], [Tooling], [Updated]) VALUES (8, N'Small', 1, CAST(N'2015-05-15 00:00:00.000' AS DateTime), N'2', CAST(N'2015-05-15 00:00:00.000' AS DateTime))
GO
SET IDENTITY_INSERT [dbo].[Tooling] OFF
I want to create a view of the table that looks like its an entirely own table.
SELECT Id, Name, Status, DateFinished
FROM Tooling t order by t.id
If i run that I would like that the records with id 5 and 7 should be excluded since they dont change in the selected set from the previous row.
I had an idea to solve this by using, ROW_NUMBER() over partition
And by using group by but thats seems to incorrect(Could not to get it to work at all)
How do I group it when the should be grouped on that the value change and not the value it contains?
Any suggestions to solve this?
My end goal is also try to convert this to linq to entities...

OK, supposing it's ordered by id
select *
from (
select *, rng = row_number() over (partition by grp order by id)
from (
select *, grp = row_number() over (order by id) - row_number() over (partition by Name, Status, DateFinished order by id)
from tooling ) g
) gn
where rng = 1
order by id

Related

How to convert rows to columns with commasepart using huge data in SQL Server

I have a question about SQL Server: how to convert rows to columns with comma-separated data using bulk data?
CREATE TABLE [dbo].[Emp]
(
[eid] [int] NULL,
[name] [varchar](50) NULL,
[sal] [money] NULL,
[doj] [date] NULL,
[deptno] [int] NULL
)
INSERT [dbo].[Emp] ([eid], [name], [sal], [doj], [deptno])
VALUES (1, N'a', 100.0000, CAST(N'2010-10-01' AS Date), 10)
INSERT [dbo].[Emp] ([eid], [name], [sal], [doj], [deptno])
VALUES (2, N'bb', 200.0000, CAST(N'2010-02-03' AS Date), 20)
INSERT [dbo].[Emp] ([eid], [name], [sal], [doj], [deptno])
VALUES (3, N'c', 300.0000, CAST(N'2017-02-03' AS Date), 30)
INSERT [dbo].[Emp] ([eid], [name], [sal], [doj], [deptno])
VALUES (4, N'd', 301.0000, CAST(N'2010-03-04' AS Date), 10)
INSERT [dbo].[Emp] ([eid], [name], [sal], [doj], [deptno])
VALUES (5, N'teee', 250.0000, CAST(N'2010-06-04' AS Date), 20)
INSERT [dbo].[Emp] ([eid], [name], [sal], [doj], [deptno])
VALUES (7, N'tte', 800.0000, CAST(N'2010-08-09' AS Date), 70)
I want output like below :
userlist
1,2,3,4,5,7
I tried this code:
select distinct
stuff((select ',' + cast(u.eid as varchar)
from emp u
where 1 = 1
for xml path('')), 1, 1, '') as userlist
from emp
Suppose if data has 100 thousand entries, then this query is not returning 100 thousand comma-separated
Could you please tell me how to write query to achieve this task in SQL Server?
I think the query is working as expected. But the result is too large to be displayed in management studio.

SQL - Summary of transactions - Calculate start end time of transactions based on column

I have a SQL table which holds transactions of products and cumulative total of packed products each minute from a machine.
I'm trying to summarize this table (in a sql query) into product runs.
The start times are denoted by the first record of the product where cumulative is > 0
The finish times are denoted by the last record of the product run - but ignore if the cumulative didn't change (i.e. no more products where actually packed)
As in the example table, the same product can have multiple runs a day but the summary should show each individual product run.
Create table and insert data....
CREATE TABLE [dbo].[Test](
[ID] [nchar](10) NULL,
[Product] [varchar](20) NULL,
[datetime] [datetime] NULL,
[Cumulative_Packed] [int] NULL
) ON [PRIMARY]
GO
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'1 ', N'Item1', CAST(N'2019-11-14T14:15:00.000' AS DateTime), 10)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'2 ', N'Item1', CAST(N'2019-11-14T14:16:00.000' AS DateTime), 22)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'3 ', N'Item1', CAST(N'2019-11-14T14:17:00.000' AS DateTime), 35)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'4 ', N'Item1', CAST(N'2019-11-14T14:18:00.000' AS DateTime), 40)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'5 ', N'Item1', CAST(N'2019-11-14T14:19:00.000' AS DateTime), 40)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'6 ', N'Item1', CAST(N'2019-11-14T14:20:00.000' AS DateTime), 40)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'7 ', N'Item1', CAST(N'2019-11-14T14:21:00.000' AS DateTime), 0)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'8 ', N'Item1', CAST(N'2019-11-14T14:22:00.000' AS DateTime), 0)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'9 ', N'Item1', CAST(N'2019-11-14T14:23:00.000' AS DateTime), 0)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'10 ', N'Item2', CAST(N'2019-11-14T14:24:00.000' AS DateTime), 12)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'11 ', N'Item2', CAST(N'2019-11-14T14:25:00.000' AS DateTime), 18)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'12 ', N'Item2', CAST(N'2019-11-14T14:26:00.000' AS DateTime), 18)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'13 ', N'Item2', CAST(N'2019-11-14T14:27:00.000' AS DateTime), 22)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'14 ', N'Item2', CAST(N'2019-11-14T14:28:00.000' AS DateTime), 22)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'15 ', N'Item1', CAST(N'2019-11-14T14:29:00.000' AS DateTime), 0)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'16 ', N'Item1', CAST(N'2019-11-14T14:30:00.000' AS DateTime), 7)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'17 ', N'Item1', CAST(N'2019-11-14T14:31:00.000' AS DateTime), 30)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'18 ', N'Item1', CAST(N'2019-11-14T14:32:00.000' AS DateTime), 38)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'19 ', N'Item1', CAST(N'2019-11-14T14:33:00.000' AS DateTime), 38)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'20 ', N'Item1', CAST(N'2019-11-14T14:34:00.000' AS DateTime), 38)
INSERT [dbo].[Test] ([ID], [Product], [datetime], [Cumulative_Packed]) VALUES (N'21 ', N'Item1', CAST(N'2019-11-14T14:35:00.000' AS DateTime), 38)
I think you want lead() and lag() to identify the starts and stops. For your data:
select row_number() over (order by min(datetime)) as run_order,
product, min(datetime), max(datetime),
max(cumulative_packed)
from (select t.*,
sum(case when prev_cp = 0 or prev_cp is null then 1 else 0 end) over (partition by product order by datetime) as rungrp
from (select t.*,
lag(cumulative_packed) over (partition by product order by datetime) as prev_cp,
lead(cumulative_packed) over (partition by product order by datetime) as next_cp
from t
) t
where (prev_cp = 0 or prev_cp is null) or -- is start
(next_cp = cp or next_cp = 0 or next_cp is null) -- is stop
) t
group by rungrp, product
order by rungrp, product, min(datetime);
EDIT:
Your data seems to require duplicate removal. From what I follow, you just need the first time the value changes. This can be handled with one additional layer of subqueries:
select row_number() over (order by min(datetime)) as run_order,
product, min(datetime), max(datetime),
max(cumulative_packed)
from (select t.*,
sum(case when prev_cp = 0 or prev_cp is null then 1 else 0 end) over (partition by product order by datetime) as rungrp
from (select t.*,
lag(cumulative_packed) over (partition by product order by datetime) as prev_cp,
lead(cumulative_packed) over (partition by product order by datetime) as next_cp
from (select t.*,
lag(cumulative_packed) over (partition by product order by datetime) as first_prev_cp
from t
) t
where first_prev_cp is null or first_prev_cp <> cumulative_packed
) t
where (prev_cp = 0 or prev_cp is null) or -- is start
(next_cp = cp or next_cp = 0 or next_cp is null) -- is stop
) t
group by rungrp, product
order by rungrp, product, min(datetime);

unpivot a sql (columns to rows)

I have a table with 7 columns and I am trying to unpivot to rows.
All the Columns starting P1Start should be a new column in new Unpivoted table.
The table should like sample_Unpivot table: P1Start, P1End, P2Start, P2End ... should be a row value.
I have attached the insert script below.
Can you please provide me the code?
CREATE TABLE [dbo].[sample](
[id] [int] NULL,
[P1StartOrderDate] [datetime] NULL,
[P1StartReceiveDate] [datetime] NULL,
[P1EndOrderDate] [datetime] NULL,
[P1EndReceiveDate] [datetime] NULL,
[P2StartOrderDate] [datetime] NULL,
[P2StartReceiveDate] [datetime] NULL,
[P2EndOrderDate] [datetime] NULL,
[P2EndReceiveDate] [datetime] NULL
)
CREATE TABLE [dbo].[sample_unpivot](
[id] [int] NULL,
[Phase] [char](30) NULL,
[OrderDate] [datetime] NULL,
[ReceiveDate] [datetime] NULL
)
INSERT [dbo].[sample] ([id], [P1StartOrderDate], [P1StartReceiveDate], [P1EndOrderDate], [P1EndReceiveDate], [P2StartOrderDate], [P2StartReceiveDate], [P2EndOrderDate], [P2EndReceiveDate]) VALUES (1, CAST(N'2020-01-01 00:00:00.000' AS DateTime), CAST(N'2020-01-03 00:00:00.000' AS DateTime), CAST(N'2020-05-01 00:00:00.000' AS DateTime), CAST(N'2010-01-01 00:00:00.000' AS DateTime), CAST(N'2020-08-01 00:00:00.000' AS DateTime), CAST(N'2020-01-11 00:00:00.000' AS DateTime), CAST(N'2020-05-03 00:00:00.000' AS DateTime), CAST(N'2020-01-04 00:00:00.000' AS DateTime))
GO
INSERT [dbo].[sample_unpivot] ([id], [Phase], [OrderDate], [ReceiveDate]) VALUES (1, N'P1Start ', CAST(N'2020-01-01 00:00:00.000' AS DateTime), CAST(N'2020-01-03 00:00:00.000' AS DateTime))
GO
INSERT [dbo].[sample_unpivot] ([id], [Phase], [OrderDate], [ReceiveDate]) VALUES (1, N'P1End ', CAST(N'2020-05-01 00:00:00.000' AS DateTime), CAST(N'2020-01-01 00:00:00.000' AS DateTime))
GO
INSERT [dbo].[sample_unpivot] ([id], [Phase], [OrderDate], [ReceiveDate]) VALUES (1, N'P2Start ', CAST(N'2020-08-01 00:00:00.000' AS DateTime), CAST(N'2020-01-11 00:00:00.000' AS DateTime))
GO
INSERT [dbo].[sample_unpivot] ([id], [Phase], [OrderDate], [ReceiveDate]) VALUES (1, N'P2End ', CAST(N'2020-05-03 00:00:00.000' AS DateTime), CAST(N'2020-01-04 00:00:00.000' AS DateTime))
GO
Your table structure suggests SQL Server syntax, so i would do :
select s.id, ss.*
from sample s cross apply
( values ('P1Start', P1StartOrderDate, P1StartReceiveDate),
('P1End', P1EndOrderDate, P1EndReceiveDate),
('P2Start', P2StartOrderDate, P2StartReceiveDate),
('P2End', P2EndOrderDate, P2EndReceiveDate)
) ss(Phase, OrderDate, ReceiveDate);
Another way you can try to use UNION ALL to make it.
select id,'P1Start' Phase, P1StartOrderDate OrderDate, P1StartReceiveDate ReceiveDate
from sample s
UNION ALL
select id,'P1End' Phase,P1EndOrderDate, P1EndReceiveDate
from sample s
UNION ALL
select id,'P2Start' Phase, P2StartOrderDate, P2StartReceiveDate
from sample s
UNION ALL
select id,'P2End' Phase, P2EndOrderDate, P2EndReceiveDate
from sample s
sqlfiddle

SQL Server : complex query to get average time

I have a complex SQL query please resolve. Here is the details of it.
As I think the screenshot I have attached shows all the requirements. The system works like this.
I am creating a text file in my application and logging the same in SQL Server also. As soon as this file gets created, with same name another file gets created with .html extension. I am logging the html file also in SQL Server. So basically if you want you can group the rows on the basis of file name to get a single request.
Now by using SQL I want to get the time difference between these two files. As you can see in the image that first request has taken 547 milliseconnds.
The same way I want to get the average time taken by all the requests in a minute or hour.
SQL Script
CREATE TABLE [dbo].[DebugInfo](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[FileName] [varchar](250) NULL,
[Message] [varchar](250) NULL,
[Time] [datetime] NULL,
[UserId] [int] NULL,
CONSTRAINT [PK_DebugInfo] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
SET IDENTITY_INSERT [dbo].[DebugInfo] ON
INSERT [dbo].[DebugInfo] ([Id], [FileName], [Message], [Time], [UserId]) VALUES (1, N'\\172.16.1.18\datadrive\vol2\SCANNING\SCAN\NovToWin\SIP1\WH000001.txt', N'File Is LOCKED Count:- 511', CAST(0x0000A43300CF83FD AS DateTime), NULL)
INSERT [dbo].[DebugInfo] ([Id], [FileName], [Message], [Time], [UserId]) VALUES (2, N'\\172.16.1.18\datadrive\vol2\SCANNING\SCAN\NovToWin\SIP1\WH000001.htm', N'File Is LOCKED Count:- 335', CAST(0x0000A43300CF84A1 AS DateTime), NULL)
INSERT [dbo].[DebugInfo] ([Id], [FileName], [Message], [Time], [UserId]) VALUES (3, N'\\172.16.1.18\datadrive\vol2\SCANNING\SCAN\NovToWin\SIP1\WH000002.txt', N'File Is LOCKED Count:- 672', CAST(0x0000A43300D0072D AS DateTime), NULL)
INSERT [dbo].[DebugInfo] ([Id], [FileName], [Message], [Time], [UserId]) VALUES (4, N'\\172.16.1.18\datadrive\vol2\SCANNING\SCAN\NovToWin\SIP1\WH000002.htm', N'File Is LOCKED Count:- 1006', CAST(0x0000A43300D00895 AS DateTime), NULL)
INSERT [dbo].[DebugInfo] ([Id], [FileName], [Message], [Time], [UserId]) VALUES (5, N'\\172.16.1.18\datadrive\vol2\SCANNING\SCAN\NovToWin\SIP1\WH000003.txt', N'File Is LOCKED Count:- 254', CAST(0x0000A43300D00FC9 AS DateTime), NULL)
INSERT [dbo].[DebugInfo] ([Id], [FileName], [Message], [Time], [UserId]) VALUES (6, N'\\172.16.1.18\datadrive\vol2\SCANNING\SCAN\NovToWin\SIP1\WH000003.htm', N'File Is LOCKED Count:- 136', CAST(0x0000A43300D01001 AS DateTime), NULL)
INSERT [dbo].[DebugInfo] ([Id], [FileName], [Message], [Time], [UserId]) VALUES (7, N'\\172.16.1.18\datadrive\vol2\SCANNING\SCAN\NovToWin\SIP1\WH000004.txt', N'File Is LOCKED Count:- 772', CAST(0x0000A43300D0167E AS DateTime), NULL)
INSERT [dbo].[DebugInfo] ([Id], [FileName], [Message], [Time], [UserId]) VALUES (8, N'\\172.16.1.18\datadrive\vol2\SCANNING\SCAN\NovToWin\SIP1\WH000004.htm', N'File Is LOCKED Count:- 181', CAST(0x0000A43300D016C5 AS DateTime), NULL)
INSERT [dbo].[DebugInfo] ([Id], [FileName], [Message], [Time], [UserId]) VALUES (9, N'\\172.16.1.18\datadrive\vol2\SCANNING\SCAN\NovToWin\SIP1\WH000005.txt', N'File Is LOCKED Count:- 347', CAST(0x0000A43300D01B65 AS DateTime), NULL)
INSERT [dbo].[DebugInfo] ([Id], [FileName], [Message], [Time], [UserId]) VALUES (10, N'\\172.16.1.18\datadrive\vol2\SCANNING\SCAN\NovToWin\SIP1\WH000005.htm', N'File Is LOCKED Count:- 117', CAST(0x0000A43300D01B8F AS DateTime), NULL)
INSERT [dbo].[DebugInfo] ([Id], [FileName], [Message], [Time], [UserId]) VALUES (11, N'\\172.16.1.18\datadrive\vol2\SCANNING\SCAN\NovToWin\SIP1\WH000006.txt', N'File Is LOCKED Count:- 572', CAST(0x0000A43300F13506 AS DateTime), NULL)
INSERT [dbo].[DebugInfo] ([Id], [FileName], [Message], [Time], [UserId]) VALUES (12, N'\\172.16.1.18\datadrive\vol2\SCANNING\SCAN\NovToWin\SIP1\WH000006.htm', N'File Is LOCKED Count:- 562', CAST(0x0000A43300F13632 AS DateTime), NULL)
Here is what i have used to generate the RawFileName
SELECT *, SUBSTRING((REVERSE
(
SUBSTRING
(
REVERSE(FileName),0,CHARINDEX('\',REVERSE(FileName))
)
)),0, CHARINDEX('.',REVERSE
(
SUBSTRING
(
REVERSE(FileName),0,CHARINDEX('\',REVERSE(FileName))
)
))) AS RawFileName from DebugInfo
Thanks
Does this do what you want?
select avg(diff_ms * 1.0)
from (select datediff(millisecond, min(time), max(time)) as diff_ms
from t
group by rawfilename
) t;
select avg(diff)
from ( select filename, DATEDIFF(MILLISECOND, Time, nextTime) as diff
from ( select [FileName]
, [Time]
, lead(Time, 1, 0) OVER (ORDER BY id) AS nextTime
, row_number() over (partition by FileName order by Time) as rn
from [DebugInfo]
) tt
where tt.rn = 1
) ttt
select avg(diff)
from ( select datediff(millisecond, minTime, maxTime) as diff
from ( select min(time) as minTime, max(time) ss maxTime
from [DebugInfo]
group by rawfilename
) tt
) ttt;

Hierarchical data with CTE

I am sorry if the answer has been posted already, but I was not able to find the answer even after searching.
I have the following table
CREATE TABLE [dbo].[emp](
[id] [int] NOT NULL,
[name] [varchar](20) NULL,
[mgrid] [int] NULL
) ON [PRIMARY]
With data
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (1, N'a', 0)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (2, N'a1', 1)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (3, N'a11', 2)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (4, N'a12', 2)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (5, N'a13', 2)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (6, N'a2', 1)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (7, N'a3', 1)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (8, N'a31', 7)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (9, N'a32', 7)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (10, N'b', 0)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (11, N'b1', 10)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (12, N'b2', 10)
And I would like the following output
a
a1
a11
a12
a13
a2
a3
a31
a32
b
b1
b2
Is this possible in SQL Server?
SQLFiddle demo
You can use ' ' instead of '+' in the last line to pad a string.
with t as
(
select id,name,mgrid,1 as level,cast(name as varchar(max)) as path
from emp where mgrid=0
union all
select emp.id,emp.name,emp.mgrid, t.level+1 as level,
t.path+cast(emp.name as varchar(max)) as path
from emp
join t on emp.mgrid=t.id
)
select replicate('+', level)+name from t order by path
with CTE as
(
select *
, level = 1
from emp
where mgrid = 0
union all
select emp.id,
name = cast(space((level) * 3) + emp.name as varchar(20)),
emp.mgrid,
level = level + 1
from emp
inner join CTE on CTE.id = emp.mgrid
)
select name
from CTE
order by ltrim(name)
Query:
DECLARE #temp TABLE
(
[id] [int] NOT NULL,
[name] [varchar](20) NULL,
[mgrid] [int] NULL
)
INSERT INTO #temp ([id], [name], [mgrid])
VALUES
(1, N'a', 0), (2, N'a1', 1),
(3, N'a11', 2), (4, N'a12', 2),
(5, N'a13', 2), (6, N'a2', 1),
(7, N'a3', 1), (8, N'a31', 7),
(9, N'a32', 7), (10, N'b', 0),
(11, N'b1', 10), (12, N'b2', 10)
DECLARE #out VARCHAR(MAX) = ''
;WITH cte AS
(
SELECT *, Lvl = 0, nn = CAST(name AS VARCHAR(MAX))
FROM #temp
WHERE mgrid = 0
UNION ALL
SELECT t.*, c.Lvl + 1, nn = CAST(REPLICATE(' ', c.Lvl + 1) + t.name AS VARCHAR(MAX))
FROM #temp t
JOIN cte c ON c.id = t.mgrid
)
SELECT #out = (
SELECT nn + CHAR(13)
FROM cte
ORDER BY LTRIM(nn)
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
PRINT #out
Output:
a
a1
a11
a12
a13
a2
a3
a31
a32
b
b1
b2
You can use CTE (Comnon table expression to achieve this)
check this sample code:
declare #emp table(
[id] [int] NOT NULL,
[name] [varchar](20) NULL,
[mgrid] [int] NULL
)
INSERT #emp ([id], [name], [mgrid]) VALUES (1, N'a', 0)
INSERT #emp ([id], [name], [mgrid]) VALUES (2, N'a1', 1)
INSERT #emp ([id], [name], [mgrid]) VALUES (3, N'a11', 2)
INSERT #emp ([id], [name], [mgrid]) VALUES (4, N'a12', 2)
INSERT #emp ([id], [name], [mgrid]) VALUES (5, N'a13', 2)
INSERT #emp ([id], [name], [mgrid]) VALUES (6, N'a2', 1)
INSERT #emp ([id], [name], [mgrid]) VALUES (7, N'a3', 1)
INSERT #emp ([id], [name], [mgrid]) VALUES (8, N'a31', 7)
INSERT #emp ([id], [name], [mgrid]) VALUES (9, N'a32', 7)
INSERT #emp ([id], [name], [mgrid]) VALUES (10, N'b', 0)
INSERT #emp ([id], [name], [mgrid]) VALUES (11, N'b1', 10)
INSERT #emp ([id], [name], [mgrid]) VALUES (12, N'b2', 10);
with cte (id,name, MGRID) as
(
select id, name,MGRID
from #emp
union all
select c.id, c.name, c.MGRID
from #emp c
inner join cte p
on c.mgrid = P.id
)
SELECT Distinct * FROM CTE
WITH RCTE AS
(
SELECT id, name, mgrid, CAST('' AS NVARCHAR(MAX)) AS blanks , CAST(name AS NVARCHAR(MAX)) AS ordr
FROM dbo.emp WHERE mgrid = 0
UNION ALL
SELECT e.id, e.name, e.mgrid, blanks + ' ' AS blanks, ordr + e.name AS ordr
FROM dbo.emp e
INNER JOIN RCTE r ON e.mgrid = r.id
)
SELECT blanks + name FROM RCTE
ORDER BY ordr