如何获取PostgreSQL中的所有类别和子类别?

How to get all the categories and sub categories in PostgreSQL?

我正在使用 .net core 5 与 EF core 和 postgres 10 创建一个小型电子商务演示应用程序。
我正在尝试获取主页上的所有类别和子类别。

这是我的类别层次结构:

男性(父类别)

女性

这是我的创建 table 和插入脚本:

CREATE TABLE category
(
    id                uuid      DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
    parent_id         uuid                                             NULL,
    name              character varying(255)                           NOT NULL,
    short_description character varying(255)                           NOT NULL,
    activate_on       date                                             NULL,
    deactivate_on     date                                             NULL,
    url_segment       character varying(255)                           NOT NULL,
    meta_keywords     character varying                                NOT NULL,
    meta_description  character varying                                NOT NULL,
    sort_order        integer                                          NOT NULL,
    created_on        timestamp DEFAULT CURRENT_TIMESTAMP,
    created_by        character varying(100),
    modified_on       timestamp DEFAULT CURRENT_TIMESTAMP,
    modified_by       character varying(100),
    is_active         boolean
);



INSERT INTO public.category (id, parent_id, name, short_description, activate_on, deactivate_on, url_segment,
                             meta_keywords, meta_description, sort_order, created_on, created_by, modified_on,
                             modified_by, is_active)
VALUES ('0ca0c27c-f45b-4768-a3cb-958bfbf6df26', '6dfdf5e4-673b-4134-b4a9-3a0b14b50e6a', 'T-Shirts', 'T-Shirts',
        '2021-02-21', NULL, 'men-tshirts',
        't shirt for mens india, t shirt for men online, polo t shirts, sport t shirt, black t shirt, blue t shirt, white t shirt',
        'Men''s T-shirts - Buy T-shirts for men online in India. Choose from a wide range of polo, round, V neck & more Men''s T-shirts in various designs at Myntra.',
        1, '2021-02-21 13:17:15.652506', 'glenn', NULL, '', TRUE);
INSERT INTO public.category (id, parent_id, name, short_description, activate_on, deactivate_on, url_segment,
                             meta_keywords, meta_description, sort_order, created_on, created_by, modified_on,
                             modified_by, is_active)
VALUES ('6927198d-9240-43b0-853a-0507cad3b529', '6dfdf5e4-673b-4134-b4a9-3a0b14b50e6a', 'Formal Shirts',
        'Formal Shirts', '2021-02-21', NULL, 'men-formal-shirts',
        'Men''s formal shirts, formal shirts for men, slim fit formal shirts for men, latest formal shirts for men, formal shirts for men online, formal shirts for men India',
        'Formal Shirts for Men - Shop for trendy men''s formal shirts online in India at Myntra. ✯Free Shipping ✯Easy returns and exchanges ✯COD',
        2, '2021-02-21 13:21:16.125333', 'glenn', NULL, '', TRUE);
INSERT INTO public.category (id, parent_id, name, short_description, activate_on, deactivate_on, url_segment,
                             meta_keywords, meta_description, sort_order, created_on, created_by, modified_on,
                             modified_by, is_active)
VALUES ('0d3f9e43-12a2-4f8c-a008-a45cbf15fedd', NULL, 'Women', 'Women', '2021-02-21', NULL, 'women',
        'women online shopping, online shopping for women, women clothing, women dresses online',
        'Online Shopping for Women. Shop Online from a wide range of womens clothing, shoes, Ladies bags & more in India @ Myntra ✯Free Shipping ✯COD ✯Easy returns and exchanges.',
        0, '2021-02-21 13:26:04.447031', 'glenn', NULL, '', TRUE);
INSERT INTO public.category (id, parent_id, name, short_description, activate_on, deactivate_on, url_segment,
                             meta_keywords, meta_description, sort_order, created_on, created_by, modified_on,
                             modified_by, is_active)
VALUES ('6dfdf5e4-673b-4134-b4a9-3a0b14b50e6a', 'eb81c712-0643-45a2-b597-129a1f9892e2', 'Topwear', 'Topwear',
        '2021-02-21', NULL, 'top-wear', 'mens topwear', 'mens topwear', 1, '2021-02-21 13:12:30.518814', 'glenn',
        NULL, '', TRUE);
INSERT INTO public.category (id, parent_id, name, short_description, activate_on, deactivate_on, url_segment,
                             meta_keywords, meta_description, sort_order, created_on, created_by, modified_on,
                             modified_by, is_active)
VALUES ('eb81c712-0643-45a2-b597-129a1f9892e2', NULL, 'Men', 'Men', '2021-02-21', NULL, 'men',
        'Men Topwear, Men Topwear in India, buy Men Topwear online in india, online store for Men Topwear, Shop online for Men Topwear, online shopping for Men Topwear, Online shopping for Men Topwear in India, reviews and prices',
        'Men Topwear Online. Shop for Men Topwear in India ? Buy latest range of Men Topwear at Myntra ? Free Shipping ? COD ? Easy returns and exchanges',
        0, '2021-02-21 13:10:29.204689', 'glenn', NULL, '', TRUE);
INSERT INTO public.category (id, parent_id, name, short_description, activate_on, deactivate_on, url_segment,
                             meta_keywords, meta_description, sort_order, created_on, created_by, modified_on,
                             modified_by, is_active)
VALUES ('731b01bd-fab7-475e-adb2-6322eb9eac68', '0d3f9e43-12a2-4f8c-a008-a45cbf15fedd', 'India & Fusion Wear',
        'India & Fusion Wear', '2021-02-21', NULL, 'fusion-wear',
        'indo western fusion dresses, fusion kurtis, fusion saree, fusion dress, designer fusion wear, ethnic fusion wear, fusion wear online, indo western fusion, fusion outfits',
        'Buy Latest Collection of Women Fusion Wear online in India. Choose From Kurtas, Designer Sarees, Dresses, Lehenga Choli & more of brands like Mitera, Anouk, Biba & more at Myntra Fashion store ✯ COD ✯ Discounts',
        1, '2021-02-21 13:32:52.616545', 'glenn', NULL, '', TRUE);
INSERT INTO public.category (id, parent_id, name, short_description, activate_on, deactivate_on, url_segment,
                             meta_keywords, meta_description, sort_order, created_on, created_by, modified_on,
                             modified_by, is_active)
VALUES ('3715c7fc-3c0e-4ee4-8fa0-dfd48e8e3a3a', '731b01bd-fab7-475e-adb2-6322eb9eac68', 'Sarees', 'Sarees',
        '2021-02-21', NULL, 'saree',
        'saree, sarees, women saree, new saree collection, fancy saree, online saree shopping, saree blouse designs,latest saree,new saree design,latest saree design, sari online',
        'Saree - Pick from the designer range of Saris online for ladies & girls. Buy formal, partywear, casual Sarees in various prints, patterns, types & more at Myntra store.',
        1, '2021-02-21 13:35:26.166935', 'glenn', NULL, '', TRUE);
INSERT INTO public.category (id, parent_id, name, short_description, activate_on, deactivate_on, url_segment,
                             meta_keywords, meta_description, sort_order, created_on, created_by, modified_on,
                             modified_by, is_active)
VALUES ('34c0d8ef-19a0-4f3a-8439-6d0510cfba04', '731b01bd-fab7-475e-adb2-6322eb9eac68', 'Kurtas & Suits',
        'Kurtas & Suits', '2021-02-21', NULL, 'women-kurtas-kurtis-suits',
        'kurtis online, designer kurti, ladies designers kurtis, designers kurtis, designer kurtis online, designers kurtis, suits online',
        'Women Kurtis & Kurtas Suits - Buy Designer Kurtas & Kurtis for Ladies online. Pick from Huge range kurtis, kurtas sets & suits for Women at Myntra ✯ COD ✯ Easy returns and exchanges',
        2, '2021-02-21 13:36:59.067196', 'glenn', NULL, '', TRUE);

我想从我的数据库中引入所有类别,以便像上面的类别层次结构一样容易绑定到 UI 端。

有人可以帮我查询吗?

------------ 已修订
Parent、Sub、Leaf的判断比较简单:

  1. 第 Child 行 ID 为空,然后 Parent。
  2. 行 child id 不为空且行有 child 行然后是子
  3. 否则叶子。

唯一的难点是上面的2。
现在可以通过几种方式将其清除:

  • 使用相同的基本递归 CTE 同时应用超前和滞后函数 在主查询中然后检查空值。但是有了层次结构,这很快就会变得混乱。所以让我们拒绝那个想法。
  • 对 CTE 稍作修改后 non-recursive select Parent秒。在递归select中查看当前是否有child行 然后是子类别。

修改 CTE 还算不错,但是 select 因为它是 parent 还是有点难看。因此,下面将其抽象为一个简单的 SQL 函数,该函数 returns 适当的类型(假定 id 已知为 child)。

create or replace 
function category_sub_or_leaf(id_in uuid)
  returns text
  language sql 
  strict 
as $$ 
    select case when exists (select null
                               from category
                               where parent_id = id_in 
                            )   
                then '(Sub Category)'
                else '(leaf level category)'
             end  ;
$$;

结果查询为:

with recursive heir (id, parent_id, name, short_description, sort_order, root_path, lev, cat_level) as
    ( select  id, parent_id, name, short_description, sort_order,(name)::text, 1, '(Parent Category)'
        from category 
       where parent_id is null
      union all 
      select c.id, c.parent_id, c.name, c.short_description, c.sort_order, root_path || '>'||(c.name)::text, lev+1    
           , category_sub_or_leaf(c.id) 
        from category c
        join heir     h 
          on c.parent_id = h.id
    ) --select * from heir;                                                              
select  (rpad(' ', 4*(lev-1),' ') || short_description) || ' ' || cat_level   description
  from heir
 order by root_path,lev,sort_order;

参见revised demo: 演示还清除了女鞋以在子类别中提供额外的层。 I.E 2层子类别。但是因为我不想打那么多字,所以我修改了 table 除了必要的列之外不需要任何东西。

------------ 原
您要查找的是 recursive cte. Here the first (non-recursive term) select gets the rows which do not have parent_id defined. Then the recursive term (after union) looks back to the previous row and retrieves the child rows. (A poor description at best.) The query builds the path back to the first parent and the current depth. These generated columns are then used to provide order and indentation of the results. See Demo.

with recursive heir as 
     ( select  id, parent_id, name, short_description, (name)::text path, 1 lev
         from category 
        where parent_id is null
       union all 
       select c.id, c.parent_id, c.name, c.short_description, path ||'>'||(c.name)::text, lev+1 
         from category c
         join heir     h 
           on c.parent_id = h.id
     ) 
select (rpad(' ', 4*(lev-1),' ') || short_description) short_description
  from heir
 order by path, lev ;

注意:演示是使用 Postgres 13 构建的,因此函数 gen_random_uuid() 代替了 uuid_generate_v4()。