Question

I have some hierarchical categories in SQL Server, defined as such:

CREATE TABLE [dbo].[CategoryDesc] (
    [CategoryId] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](255) NOT NULL
)

CREATE TABLE [dbo].[CategoryRelationship] (
    [RelationshipId] [int] IDENTITY(1,1) NOT NULL,
    [CategoryId] [int] NOT NULL,
    [ParentId] [int] NULL
)

CREATE TABLE [dbo].[Machine] (
    [MachineId] [int] IDENTITY(1,1) NOT NULL,
    [Make] [varchar](50) NOT NULL,
    [Model] [varchar](255) NOT NULL,
    [CreateDate] [datetime] NOT NULL,
    [CategoryId] [int] NOT NULL
)

NB: Primary keys, relationships and some fields omitted for brevity.

I already use CTE's to be able to produce a full tree, an excerpt of which outputs:

Foundry/Forging
Foundry/Forging > Core Equipment
Foundry/Forging > Furnaces
Foundry/Forging > Furnaces > Induction
Glass
Glass > Bevelling
Glass > Cutting
Glass > Cutting > Laminated Glass
Glass > Cutting > Manual
Glass > Cutting > Shape
Glass > Cutting > Straight
Glass > Decorating
Glass > Drilling
Glass > Drilling > Horizontal
Glass > Drilling > Vertical
etc

I need a query that given the top-level categoryId, returns the latest machine added (based on CreateDate) regardless of which child category and at which level it was added.

The problem I'm having is that machines may be added to either 2nd or 3rd level categories (although never the top level) and CTE's don't allow left joins on the recursion part.

Thanks in advance for any help given. :)

Was it helpful?

Solution

I have simplified your schema to:

create table cat( id int, name varchar(100) );
create table tree ( id int , parent_id int);
create table item( id int, name varchar(100), cat_id int);

insert into cat values 
( 1, 'HW'),
( 2, 'HW-PC'),
( 3, 'HW-M' ),
( 4, 'Soft'),
(5,'HW-M-N');

insert into tree values
(2,1),
(3,1),
(5,3);

insert into item values 
( 1, 'A', 2),
( 2, 'B', 3);

The query you request, for root category = 1 is:

with child_id as
( 
  select parent_id as id
      from tree
      where parent_id = 1                         --here cat = 1
   union all
   select tree.id
   from child_id  c
   inner join tree on tree.parent_id = c.id
),
productes as (
   select item.*,
    row_number() over (order by item.id ) as rn  --set your order criteria
   from item 
   inner join child_id c on c.id = item.cat_id
)
select * 
 from productes
where rn = 1

Results:

| ID | NAME | CAT_ID | RN |
---------------------------
|  1 |    A |      2 |  1 |
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top