SQL Clone
SQLServerCentral is supported by Redgate
 
Log in  ::  Register  ::  Not logged in
 
 
 


Build menu with CTE ....


Build menu with CTE ....

Author
Message
dwain.c
dwain.c
SSCertifiable
SSCertifiable (7.3K reputation)SSCertifiable (7.3K reputation)SSCertifiable (7.3K reputation)SSCertifiable (7.3K reputation)SSCertifiable (7.3K reputation)SSCertifiable (7.3K reputation)SSCertifiable (7.3K reputation)SSCertifiable (7.3K reputation)

Group: General Forum Members
Points: 7289 Visits: 6431
hunchback (9/22/2013)
One way to accomplish this is using a varbinary column to concatenate the sequence of numbers based on the position value.


WITH C1 AS (
SELECT
Id, IdRoot, Name, Position,
CAST(ROW_NUMBER() OVER(ORDER BY position) AS varbinary(900)) AS order_val,
0 AS lvl
FROM
menu
WHERE
IdRoot = 0

UNION ALL

SELECT
C.Id, C.IdRoot, C.Name, C.Position,
CAST(P.[path] + CAST(ROW_NUMBER() OVER(PARTITION BY P.IdRoot ORDER BY C.Position) AS BINARY(8)) AS varbinary(900)),
P.lvl + 1
FROM
C1 AS p
INNER JOIN
menu AS C
ON p.Id = C.IdRoot
)
SELECT REPLICATE(SPACE(4), 2 * lvl) + [name] AS menu
FROM C1
ORDER BY order_val;
GO

/*

menu
ERP
ACC
HR
PAYMENT
PROCESS
CANCEL
VACATIONS
ABSENTS
SALES

*/




To generate the numbers in specific order we can use a ranking function like ROW_NUMBER, where you can use multiple columns to drive the sort order (by name or position or whatever other combination).

You can read more about other uses of he ranking functions in the last book from Itzik Ben-Gan about T-SQL Querying.

Inside Microsoft® SQL Server® 2008: T-SQL Querying

Microsoft SQL Server 2012 High-Performance T-SQL Using Window Functions


As Jeff said, NM=Nice Method (?).

Except I think that P.[Path] should be p.Order_val in the recursive leg of your CTE.


My mantra: No loops! No CURSORs! No RBAR! Hoo-uh!

My thought question: Have you ever been told that your query runs too fast?

My advice:
INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.


Need to UNPIVOT? Why not CROSS APPLY VALUES instead?
Since random numbers are too important to be left to chance, let's generate some!
Learn to understand recursive CTEs by example.
Splitting strings based on patterns can be fast!
My temporal SQL musings: Calendar Tables, an Easter SQL, Time Slots and Self-maintaining, Contiguous Effective Dates in Temporal Tables
PiMané
PiMané
Ten Centuries
Ten Centuries (1K reputation)Ten Centuries (1K reputation)Ten Centuries (1K reputation)Ten Centuries (1K reputation)Ten Centuries (1K reputation)Ten Centuries (1K reputation)Ten Centuries (1K reputation)Ten Centuries (1K reputation)

Group: General Forum Members
Points: 1024 Visits: 1334
dwain.c (9/23/2013)
As Jeff said, NM=Nice Method (?).

Except I think that P.[Path] should be p.Order_val in the recursive leg of your CTE.


Yes, had to change it to work but it's just fine... :-)

Pedro



If you need to work better, try working less...
dwain.c
dwain.c
SSCertifiable
SSCertifiable (7.3K reputation)SSCertifiable (7.3K reputation)SSCertifiable (7.3K reputation)SSCertifiable (7.3K reputation)SSCertifiable (7.3K reputation)SSCertifiable (7.3K reputation)SSCertifiable (7.3K reputation)SSCertifiable (7.3K reputation)

Group: General Forum Members
Points: 7289 Visits: 6431
PiMané (9/23/2013)
dwain.c (9/23/2013)
As Jeff said, NM=Nice Method (?).

Except I think that P.[Path] should be p.Order_val in the recursive leg of your CTE.


Yes, had to change it to work but it's just fine... :-)

Pedro


Figured you must've.

I looked at this in the morning but didn't have time, so I came back to study it. Any time Jeff approves of something it makes me want to understand.

Now I think I do so I'm probably the better for it.


My mantra: No loops! No CURSORs! No RBAR! Hoo-uh!

My thought question: Have you ever been told that your query runs too fast?

My advice:
INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.


Need to UNPIVOT? Why not CROSS APPLY VALUES instead?
Since random numbers are too important to be left to chance, let's generate some!
Learn to understand recursive CTEs by example.
Splitting strings based on patterns can be fast!
My temporal SQL musings: Calendar Tables, an Easter SQL, Time Slots and Self-maintaining, Contiguous Effective Dates in Temporal Tables
hunchback
hunchback
SSC Veteran
SSC Veteran (229 reputation)SSC Veteran (229 reputation)SSC Veteran (229 reputation)SSC Veteran (229 reputation)SSC Veteran (229 reputation)SSC Veteran (229 reputation)SSC Veteran (229 reputation)SSC Veteran (229 reputation)

Group: General Forum Members
Points: 229 Visits: 639
I changed [path] by order_val in the recursive part and now it should run flawless.

A recursive CTE is still an iterative approach so I do not hold my breath hoping for better performance.

You can add a clustered index by ID and a nonclustered by IdRoot.



PiMané
PiMané
Ten Centuries
Ten Centuries (1K reputation)Ten Centuries (1K reputation)Ten Centuries (1K reputation)Ten Centuries (1K reputation)Ten Centuries (1K reputation)Ten Centuries (1K reputation)Ten Centuries (1K reputation)Ten Centuries (1K reputation)

Group: General Forum Members
Points: 1024 Visits: 1334
hunchback (9/23/2013)
I changed [path] by order_val in the recursive part and now it should run flawless.

A recursive CTE is still an iterative approach so I do not hold my breath hoping for better performance.

You can add a clustered index by ID and a nonclustered by IdRoot.


It's better than the recursive cursor it's currently using...
Instead of 7ms and 530reads, for 28 rows, takes 3ms and 321 reads.
And for bigger menus the difference is even greater.

Pedro



If you need to work better, try working less...
Jeff Moden
Jeff Moden
SSC Guru
SSC Guru (86K reputation)SSC Guru (86K reputation)SSC Guru (86K reputation)SSC Guru (86K reputation)SSC Guru (86K reputation)SSC Guru (86K reputation)SSC Guru (86K reputation)SSC Guru (86K reputation)

Group: General Forum Members
Points: 86041 Visits: 41095
The "NM" stands for "Never Mind". I had posted a rebuttal saying that the code didn't sort alphabetically, which seemed logical to me at the time. Then I realized that it did sort by the given ID using the same sort method that I had in my first article on hierarchies, compared it to the order the OP was looking for, and realized my mistake. I removed my mistaken post and, since we can't delete posts, just put in a quick "NM".

Still, it is a nice method... especially since I've used the same method in the past. :-)

--Jeff Moden

RBAR is pronounced ree-bar and is a Modenism for Row-By-Agonizing-Row.
First step towards the paradigm shift of writing Set Based code:
Stop thinking about what you want to do to a row... think, instead, of what you want to do to a column.
If you think its expensive to hire a professional to do the job, wait until you hire an amateur. -- Red Adair

Helpful Links:
How to post code problems
How to post performance problems
Forum FAQs
Jeff Moden
Jeff Moden
SSC Guru
SSC Guru (86K reputation)SSC Guru (86K reputation)SSC Guru (86K reputation)SSC Guru (86K reputation)SSC Guru (86K reputation)SSC Guru (86K reputation)SSC Guru (86K reputation)SSC Guru (86K reputation)

Group: General Forum Members
Points: 86041 Visits: 41095
hunchback (9/23/2013)
I changed [path] by order_val in the recursive part and now it should run flawless.

A recursive CTE is still an iterative approach so I do not hold my breath hoping for better performance.

You can add a clustered index by ID and a nonclustered by IdRoot.


Well said. Oddly enough, a well constructed WHILE loop that iterates over the Levels of the menu in a manner similar to the rCTE would probably do as well. In either case, the recursion is necessary and isn't as bad as an rCTE that counts because the rCTE method that we both used (and a similar WHILE loop would use) processes an entire set (all nodes at a given level) instead of just individual rows.

--Jeff Moden

RBAR is pronounced ree-bar and is a Modenism for Row-By-Agonizing-Row.
First step towards the paradigm shift of writing Set Based code:
Stop thinking about what you want to do to a row... think, instead, of what you want to do to a column.
If you think its expensive to hire a professional to do the job, wait until you hire an amateur. -- Red Adair

Helpful Links:
How to post code problems
How to post performance problems
Forum FAQs
Go


Permissions

You can't post new topics.
You can't post topic replies.
You can't post new polls.
You can't post replies to polls.
You can't edit your own topics.
You can't delete your own topics.
You can't edit other topics.
You can't delete other topics.
You can't edit your own posts.
You can't edit other posts.
You can't delete your own posts.
You can't delete other posts.
You can't post events.
You can't edit your own events.
You can't edit other events.
You can't delete your own events.
You can't delete other events.
You can't send private messages.
You can't send emails.
You can read topics.
You can't vote in polls.
You can't upload attachments.
You can download attachments.
You can't post HTML code.
You can't edit HTML code.
You can't post IFCode.
You can't post JavaScript.
You can post emoticons.
You can't post or upload images.

Select a forum

































































































































































SQLServerCentral


Search