Sql Select using CTE to order a recursive data - sql

Please i want a solution for this problem using CTE in SQL Server
Example for the situation
Equation 0 = 0.25*Equation 1
Equation 1 = Equation 2 + Equation 3 + 0.5*Equation 5
Equation 2 = 15 + 40
Equation 3 = Equation 6 + Equation 7
Equation 4 = 10
Equation 5 = 10 + Equation 4
Equation 6 = 10 +5
Equation 7 = Equation 5 + Equation 2
The structure of the tables is
The Element Table
ID | Name
-------|--------------
0 | Equation 0
1 | Equation 1
2 | Equation 2
3 | Equation 3
4 | Equation 4
5 | Equation 5
6 | Equation 6
7 | Equation 7
---------------------
the table holds all items of each equation
The equation Table
FK | Item | Type
-------|-----------|------------------
0 | 0.25 | constant
0 | * | Operator
0 | 1 | Element
1 | 2 | Element
1 | + | Operator
1 | 3 | Element
1 | + | Operator
1 | 0.5 | constant
1 | * | Operator
1 | 5 | Element
2 | 15 | constant
2 | + | Operator
2 | 40 | constant
… | |
… | |
… etc | |
------------------------------------
if the type is element this means it is an element item
is there any sql statement result to the correct order that i must use to calculate these equations one by one without using recursive functions because it is limited in SQL
the alternative is to calculate the last equation without any requirements then calculate the upper ones as when i need an equation i find it calculated already without recursing the equations
i need the sql select statement to produce the following order
Equation 2
Equation 6
Equation 4
Equation 5
Equation 7
Equation 3
Equation 1
Equation 0
i ordered them by eye because it is simple example
is there any select statement is used to do so
or the user must order them manually ???
... Update
1. with a fully working test scenario
The Script to create tables
/****** Object: Table [dbo].[Element] Script Date: 26/03/2017 11:10:10 م ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Element](
[Id] [int] NOT NULL,
[Name] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_Element] 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
/****** Object: Table [dbo].[Equation] Script Date: 26/03/2017 11:10:10 م ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Equation](
[fk] [int] NOT NULL,
[Item] [nvarchar](50) NOT NULL,
[Type] [nvarchar](50) NOT NULL
) ON [PRIMARY]
GO
INSERT [dbo].[Element] ([Id], [Name]) VALUES (0, N'Equation 0')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (1, N'Equation 1')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (2, N'Equation 2')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (3, N'Equation 3')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (4, N'Equation 4')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (5, N'Equation 5')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (6, N'Equation 6')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (7, N'Equation 7')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (0, N'0.25', N'constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (0, N'*', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (0, N'1', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'2', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'3', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'0.5', N'constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'*', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'5', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (2, N'15', N'constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (2, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (2, N'40', N'constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (3, N'6', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (3, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (3, N'7', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (4, N'10', N'Constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (5, N'10', N'Constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (5, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (5, N'4', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (6, N'10', N'Constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (6, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (6, N'5', N'Constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (7, N'5', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (7, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (7, N'2', N'Element')
*
#Gordon Linoff
... Thanks a lot for your care but i found some errors using the provided script that i cant solve as it is the first time for me to use CTE
The second script gives me some errors that i cant solve
the first script gives me errors as well that i cant solve

You can try it like this:
WITH Related AS
(
SELECT *
FROM Equation AS eq
LEFT JOIN Element AS e ON eq.[Type]='Element' AND eq.Item=CAST(e.Id AS VARCHAR(10))
WHERE eq.[Type]='Element'
)
,Dependecies AS
(
SELECT e.*
,ISNULL(r.Name,'') AS DepName
FROM Element AS e
LEFT JOIN Related AS r ON e.Id=r.fk
)
,recCTE AS
(
SELECT 1 AS lvl,d.Id,d.Name,d.DepName
FROM Dependecies AS d
WHERE d.Name NOT IN(SELECT x.DepName FROM Dependecies AS x)
UNION ALL
SELECT r.lvl+1,d.Id,d.Name,d.DepName
FROM recCTE AS r
INNER JOIN Dependecies AS d ON r.DepName=d.Name
)
,Ranked AS
(
SELECT Name
,DENSE_RANK() OVER(ORDER BY CASE WHEN DepName='' THEN 1000 ELSE lvl END DESC) AS Rnk
FROM recCTE
)
SELECT Name,MIN(Rnk) AS Rnk
FROM Ranked
GROUP BY Name
ORDER BY Min(Rnk)
The result
Equation 2 1
Equation 4 1
Equation 6 1
Equation 5 2
Equation 7 3
Equation 3 4
Equation 1 5
Equation 0 6
Explanation
There is a list of CTEs:
The first CTE will bind the Elements to Equation rows, where the type is Element.
The second will list all Elements with their dependencies
The third CTE is a recursive CTE, starting with the element without any dependecies, working down the dependency path
The next CTE uses DENSE_RANK() OVER() to get the calls ordered
The final SELECT returns each element and the earliest moment it is needed.

Oh, it would be swell if we could express this as:
with cte as (
select e.fk, 1 as lev
from equation e
group by e.fk
having sum(case when type = 'Element' then 1 else 0 end) = 0
union all
select e.fk, max(cte.lev) + 1
from equation e left join
cte
on e.fk = cte.fk
group by e.fk
having count(*) = count(cte.fk)
)
But that is not possible. So, we have to think in terms of string manipulation (I think). This results in putting the dependencies in a string and repeatedly chopping elements off of the string. If I have this right:
with eq as (
select e.fk,
stuff( (select ',' + e2.item
from equation e2
where e2.fk = e.fk and e2.type = 'Element'
order by e2.item
for xml path ('')
), 1, 1, '') as elements
from (select distinct e.fk from equation e) e
)
select e.fk, '' as elements_found, 1 as lev
from eq
where elements = ''
union all
select eq.fk, substring(elements_found, charindex(',', elements_found + ',') + 1), 2 as lev
from eq join
cte
on cte.elements_found like eq.fk + ',%' and eq.fk = cte.fk
where eq.type = 'Element'
)
select cte.fk, max(lev)
from cte
group by cte.fk
order by max(lev);

Related

SQL recursion on a self-referencing table to obtain specific order

I have a table as below:
Id
LinkSlug
ParentPageId
Order
1
home
0
2
page2
1
3
page3
2
4
page11
1
0
5
page12
1
1
6
page13
1
2
7
page21
2
0
8
page22
2
1
9
page121
5
0
10
page122
5
1
11
page123
5
2
I'm sure you can already see the pattern - each Page can have any number of "SubPages" defined by the ParentPageId
I've been trying to get a query that can produce the following ordered output (without using the LinkSlug alphabetical ordering because they can be anything):
Id
LinkSlug
ParentPageId
Order
1
home
0
4
page11
1
0
5
page12
1
1
9
page121
5
0
10
page122
5
1
11
page123
5
2
6
page13
1
2
2
page2
1
7
page21
2
0
8
page22
2
1
3
page3
2
I tried doing some self-joins and grouping but ended up with only one level of recursion so it was no good for the 3rd and potentially nth degree sub pages, and then also tried using a CTE as I understand they're good for recursive queries but somehow ended up producing the same table I started with and am now at a loss!
The more I try the worse it gets - I know I need to effectively select top levels (with null ParentPageId) ordered by [Order], then inject wherever there's sub pages ordering by [Order], and repeat until there are no children left - but no idea how to do this in SQL.
View on DB Fiddle
And here's the fiddle script just in case:
CREATE TABLE [Pages](
[Id] [int] IDENTITY(1,1) NOT NULL,
[LinkSlug] [nvarchar](450) NOT NULL,
[ParentPageId] [int] NULL,
[Order] [int] NOT NULL
);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (1, 'home', NULL, 0);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (2, 'page2', NULL, 1);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (3, 'page3', NULL, 2);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (4, 'page11', 1, 0);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (5, 'page12', 1, 1);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (6, 'page13', 1, 2);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (7, 'page21', 2, 0);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (8, 'page22', 2, 1);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (9, 'page121', 5, 0);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (10, 'page122', 5, 1);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (11, 'page123', 5, 2);
You would need a recursive CTE to build the hierarchy and maintain the sequence
Example
with cte1 as (
Select [Id]
,[LinkSlug]
,[ParentPageId]
,[Order]
,Seq = cast(10000+Row_Number() over (Order by [Order]) as varchar(500))
From pages
Where [ParentPageId] is null
Union All
Select cte2.[Id]
,cte2.[LinkSlug]
,cte2.[ParentPageId]
,cte2.[Order]
,Seq = cast(concat(cte1.Seq,'.',10000+Row_Number() over (Order by cte2.[Order])) as varchar(500))
From pages cte2
Join cte1 on cte2.[ParentPageId] = cte1.[Id])
Select *
From cte1
Order By Seq
Results
You can try this:
WITH cte_org (n, id,
LinkSlug,
ParentPageId) AS (
SELECT
CAST([order] as CHAR(200)),
id,
LinkSlug,
ParentPageId
FROM
pages
WHERE ParentPageId IS NULL
UNION ALL
SELECT
o.n || '_' || e.[order],
e.id,
e.LinkSlug,
e.ParentPageId
FROM
pages e
INNER JOIN cte_org o
ON o.id = e.ParentPageId)
SELECT * FROM cte_org order by n;
Note: that in MS SQL you need to use concat instead of ||; in MySQL - +

First character replace in SQL Server

I have a question about SQL Server. How to replace only 1st character value when same character have multiple times?
CREATE TABLE [dbo].[productdetails]
(
[pid] [int] NULL,
[productName] [varchar](100) NULL
)
INSERT INTO [dbo].[productdetails] ([pid], [productName])
VALUES (1, N'cinphol')
INSERT INTO [dbo].[productdetails] ([pid], [productName])
VALUES (2, N'apple')
INSERT INTO [dbo].[productdetails] ([pid], [productName])
VALUES (3, N'ppens')
INSERT INTO [dbo].[productdetails] ([pid], [productName])
VALUES (4, N'penrpos')
GO
Based on this data, I want output like this:
pid | productname
----+------------
1 | cinZhol
2 | azple
3 | zpens
4 | zenrpos
My query:
select
pid, replace(productname, 'p', 'z') productname
from
productdetails
This query is not returning the expected results.
Could you please tell me how to achieve this task in SQL Server ?
select
pid,
replace(left(productname, 1), 'p', 'z') +
substring(productname, 2, len(productname)) productname
from
productdetails

How to query SQL dynamic lookup

I have to pull data from these tables
**PRODUCT** **LOOKUP_CATEGORY**
ID ProductName ID Category
1 Memory1 1 Product Type
2 Memory2 2 DIMM Type
3 Headset1 3 Color
4 Headset2 4 Speed
5 Keyboard1 5 Form Factor
6 Keyboard2
**LOOKUP**
ID CategoryID Value
1 1 DRAM
2 1 Keyboard
3 1 Headset
4 2 Buffered
5 2 Unbuffered
6 3 Red
7 3 White
8 3 Yellow
9 4 2000Mhz
10 4 2300Mhz
11 4 2600Mhz
12 5 DIMM
13 5 SODIMM
14 5 Earbud
15 5 On-Ear
**PRODUCT_FEATURES**
ID ProductID LookupID
1 1 1
2 1 4
3 1 10
4 1 12
5 2 1
6 2 5
7 2 9
8 2 13
9 3 3
10 3 7
11 3 15
12 4 3
13 4 6
14 4 14
15 5 2
16 5 7
17 6 2
18 6 8
I would like to get the result set like this
ProductName Type DIMMType Color Speed FormFactor
Memory1 DRAM Buffered NULL 2300Mhz DIMM
Memory2 DRAM Unbuffered NULL 2000Mhz SODIMM
Headset1 Headset NULL White NULL On-Ear
Headset2 Headset NULL Red NULL Earbud
Keyboard1 Keyboard NULL White NULL NULL
Keyboard2 Keyboard NULL Yellow NULL NULL
Basically, I would like to be able to get all the products.
How do I this without making function calls? My database is Microsoft SQL 2016
I have tried this, but it does not seem to work as expected because of those NULL values
Select p.ProductID, p.ProductNumber
, lType.Value AS ProductType, lDimm.Value AS DimmType, lSpeed.Value AS Speed, lColor.Value AS Color, lFactor.Value AS FormFactor
From PRODUCT p
Left Join PRODUCT_FEATURES xType On p.ProductID = xType.ProductID
Inner Join LOOKUP lType On xType.LookupID = lType.LookupID
Inner Join LOOKUP_CATEGORY lcType On lType.CategoryID = lcType.LookupCategoryID And lcType.Category = 'Product Type'
Left Join PRODUCT_FEATURES xDimm On p.ProductID = xDimm.ProductID
Inner Join LOOKUP lDimm On xDimm.LookupID = lDimm.LookupID
Inner Join LOOKUP_CATEGORY lcDimm On lDimm.CategoryID = lcDimm.LookupCategoryID And lcDimm.Category = 'DIMM Type'
Left Join PRODUCT_FEATURES xSpeed On p.ProductID = xSpeed.ProductID
Inner Join LOOKUP lSpeed On xSpeed.LookupID = lSpeed.LookupID
Inner Join LOOKUP_CATEGORY lcSpeed On lSpeed.CategoryID = lcSpeed.LookupCategoryID And lcSpeed.Category = 'Speed'
Left Join PRODUCT_FEATURES xColor On p.ProductID = xColor.ProductID
Inner Join LOOKUP lColor On xColor.LookupID = lColor.LookupID
Inner Join LOOKUP_CATEGORY lcColor On lColor.CategoryID = lcColor.LookupCategoryID And lcColor.Category = 'Color'
Left Join PRODUCT_FEATURES xFactor On p.ProductID = xFactor.ProductID
Inner Join LOOKUP lFactor On xFactor.LookupID = lFactor.LookupID
Inner Join LOOKUP_CATEGORY lcFactor On lFactor.CategoryID = lcFactor.LookupCategoryID And lcFactor.Category = 'Form Factor'
Grouping might be able to simplify it a bit.
SELECT
f.ProductID,
p.ProductName,
MAX(CASE WHEN lc.Category = 'Product Type' THEN l.Value END) AS ProductType,
MAX(CASE WHEN lc.Category = 'DIMM Type' THEN l.Value END) AS DimmType,
MAX(CASE WHEN lc.Category = 'Speed' THEN l.Value END) AS Speed,
MAX(CASE WHEN lc.Category = 'Color' THEN l.Value END) AS Color,
MAX(CASE WHEN lc.Category = 'Form Factor' THEN l.Value END) AS FormFactor
FROM PRODUCT_FEATURES f
LEFT JOIN PRODUCT p ON p.ID = f.ProductID
LEFT JOIN LOOKUP l ON l.ID = f.LookupID
LEFT JOIN LOOKUP_CATEGORY lc ON lc.ID = l.CategoryID
GROUP BY f.ProductID, p.ProductName
You could also write it as below, if you want it truely to be dynamic you'd have to generate the statement below using dynamic SQL techniques, see SQL Server dynamic PIVOT query?:
Select ProductId,
ProductName,
Test.[Product type],
Test.[DIMM Type],
Test.[Speed],
Test.[Color],
Test.[Form Factor]
From
(SELECT
P.ProductID,
p.ProductName,
Category,
value
FROM imp.PRODUCT_FEATURES f
LEFT JOIN imp.PRODUCT p ON p.productID = f.ProductID
LEFT JOIN imp.LOOKUP l ON l.lookupID = f.LookupID
LEFT JOIN imp.LOOKUP_CATEGORY lc ON lc.lookupcategoryID = l.CategoryID
) dt
pivot (max(dt.[value]) for dt.[CATEGORY] in ([Product type],[DIMM Type],[Speed],[Color],[Form Factor])) as test
For convenience..
--Create the schema IMP first..
/****** Object: Table [imp].[Lookup] Script Date: 8/1/2018 1:48:28 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [imp].[Lookup](
[lookupID] [float] NULL,
[CategoryID] [float] NULL,
[Value] [nvarchar](255) NULL
) ON [PRIMARY]
GO
/****** Object: Table [imp].[Lookup_category] Script Date: 8/1/2018 1:48:28 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [imp].[Lookup_category](
[lookupcategoryID] [float] NULL,
[Category] [nvarchar](255) NULL
) ON [PRIMARY]
GO
/****** Object: Table [imp].[Product] Script Date: 8/1/2018 1:48:28 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [imp].[Product](
[ProductID] [float] NULL,
[ProductName] [nvarchar](255) NULL
) ON [PRIMARY]
GO
/****** Object: Table [imp].[Product_features] Script Date: 8/1/2018 1:48:28 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [imp].[Product_features](
[ID] [float] NULL,
[ProductID] [float] NULL,
[LookupID] [float] NULL
) ON [PRIMARY]
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (1, 1, N'DRAM')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (2, 1, N'Keyboard')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (3, 1, N'Headset')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (4, 2, N'Buffered')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (5, 2, N'Unbuffered')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (6, 3, N'Red')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (7, 3, N'White')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (8, 3, N'Yellow')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (9, 4, N'2000Mhz')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (10, 4, N'2300Mhz')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (11, 4, N'2600Mhz')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (12, 5, N'DIMM')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (13, 5, N'SODIMM')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (14, 5, N'Earbud')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (15, 5, N'On-Ear')
GO
INSERT [imp].[Lookup_category] ([lookupcategoryID], [Category]) VALUES (1, N'Product Type')
GO
INSERT [imp].[Lookup_category] ([lookupcategoryID], [Category]) VALUES (2, N'DIMM Type')
GO
INSERT [imp].[Lookup_category] ([lookupcategoryID], [Category]) VALUES (3, N'Color')
GO
INSERT [imp].[Lookup_category] ([lookupcategoryID], [Category]) VALUES (4, N'Speed')
GO
INSERT [imp].[Lookup_category] ([lookupcategoryID], [Category]) VALUES (5, N'Form Factor')
GO
INSERT [imp].[Product] ([ProductID], [ProductName]) VALUES (1, N'Memory1')
GO
INSERT [imp].[Product] ([ProductID], [ProductName]) VALUES (2, N'Memory2')
GO
INSERT [imp].[Product] ([ProductID], [ProductName]) VALUES (3, N'Headset1')
GO
INSERT [imp].[Product] ([ProductID], [ProductName]) VALUES (4, N'Headset2')
GO
INSERT [imp].[Product] ([ProductID], [ProductName]) VALUES (5, N'Keyboard1')
GO
INSERT [imp].[Product] ([ProductID], [ProductName]) VALUES (6, N'Keyboard2')
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (1, 1, 1)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (2, 1, 4)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (3, 1, 10)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (4, 1, 12)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (5, 2, 1)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (6, 2, 5)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (7, 2, 9)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (8, 2, 13)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (9, 3, 3)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (10, 3, 7)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (11, 3, 15)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (12, 4, 3)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (13, 4, 6)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (14, 4, 14)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (15, 5, 2)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (16, 5, 7)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (17, 6, 2)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (18, 6, 8)
GO

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

Add not relevant column to group by script

This is my sample table and values:
CREATE TABLE [dbo].[Test]
(
[Id] BIGINT NOT NULL DEFAULT(0),
[VId] BIGINT NOT NULL DEFAULT(0),
[Level] INT NOT NULL DEFAULT(0)
);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (100, 1, 1);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (101, 1, 2);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (102, 1, 3);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (103, 2, 1);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (104, 3, 1);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (105, 3, 2);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (106, 4, 1);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (107, 4, 2);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (108, 4, 3);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (109, 4, 4);
So at now I use this script:
SELECT
[T].[VId], MAX ([T].[Level]) AS [MaxLevel]
FROM
[dbo].[Test] AS [T]
GROUP BY
[T].[VId];
And it returns:
VId MaxLevel
1 3
2 1
3 2
4 4
But I need Id column also and I can't add it to Group by script, I need the following values:
VId MaxLevel Id
1 3 102
2 1 103
3 2 105
4 4 109
What is your suggestion?
Also The following values is enough The Id's With Max(Level) in any VId :
Id
102
103
105
109
A 2008 take on the question, since that's what you're working with:
declare #Test table
(
[Id] BIGINT NOT NULL DEFAULT(0),
[VId] BIGINT NOT NULL DEFAULT(0),
[Level] INT NOT NULL DEFAULT(0)
);
INSERT INTO #Test ([Id], [VId], [Level])
VALUES (100, 1, 1),(101, 1, 2),(102, 1, 3),(103, 2, 1),(104, 3, 1),
(105, 3, 2),(106, 4, 1),(107, 4, 2),(108, 4, 3),(109, 4, 4);
;With Numbered as (
select *,
RANK() OVER (PARTITION BY VId ORDER BY [Level] desc) as rn
from #Test)
select VId,Level,Id from Numbered where rn=1
Note that (as with the other solutions) this will output multiple rows per VId if there are two rows with the same maximum level. If you don't want that, switch RANK() to ROW_NUMBER() and an arbitrary one will win - or if you want a specific winner in the case of a tie, add that condition into the ORDER BY of the window function.
Use joining with the same table by VId column
something like this:
SELECT [T].[VId], [T].[MaxLevel], [T1].[Id]
FROM [dbo].[Test] AS [T1] JOIN
(SELECT [T].[VId], MAX ([T].[Level]) AS [MaxLevel]
FROM [dbo].[Test] AS [T]
GROUP BY [T].[VId]) AS [T]
ON [T1].[VId] = [T].[VId]
AND [T1].[Level] = [T].[MaxLevel]
ORDER BY [T].[VId];
the result will be:
VId MaxLevel Id
1 3 102
2 1 103
3 2 105
4 4 109
Use this:
WITH LastLevels AS
(
SELECT
[T].[VId] AS [VID],
MAX ([T].[Level]) AS [MaxLevel]
FROM [dbo].[Test] AS [T]
GROUP BY [T].[VId]
)
SELECT [LastLevels].[VID],[LastLevels].[MaxLevel], [Te].[Id]
FROM [dbo].[Test] AS [Te]
INNER JOIN [LastLevels]
ON [LastLevels].[VID]=[Te].[VId]
AND [LastLevels].[MaxLevel]=[Te].[Level]
ORDER BY [LastLevels].[VID];
SELECT ID, [VId], [MaxLevel] From
(
SELECT
[T].[VId], MAX ([T].[Level]) AS [MaxLevel]
FROM
[dbo].[Test] AS [T]
GROUP BY
[T].[VId]
)K
INNER JOIN [Test] T on T.[VId] = K.[VId] and T.[Level] = K.MaxLevel