SQL to join one table to another table multiple times? (Mapping products to categories)

前端 未结 4 1959
北海茫月
北海茫月 2021-02-04 19:54

Let\'s say I have a Product, Category, and Product_To_Category table. A Product can be in multiple categories.

    Product             


        
相关标签:
4条回答
  • 2021-02-04 19:59

    I don't know what RDBMS you're using, but in MySQL you can use GROUP_CONCAT:

    SELECT
      p.name,
      GROUP_CONCAT(c.name SEPARATOR ', ') AS categories
    FROM
      product p
      JOIN product_to_category pc ON p.id = pc.product_id
      JOIN category c ON c.id = pc.category_id
    GROUP BY
      p.name
    ORDER BY
      p.name,
      c.name
    
    0 讨论(0)
  • 2021-02-04 20:11
    SELECT p.name, cat_food.name, cat_flowers.name
    FROM
      product p
      left outer join  Product_to_category pc_food 
        on p.id = pc_food.Prod_id
      left outer join Category cat_food
        on pc_food.Cat_id = cat_food.id
        AND cat_food.name = 'Food'
      left outer join  Product_to_category pc_flowers
        on p.id = pc_flowers.Prod_id
      left outer join Category cat_flowers
        on pc_flowers.Cat_id = cat_flowers.id
        AND cat_flowers.Name = 'Flowers'
    

    It only works if you know the number of possible categories, to put them into columns. That's how (standard) SQL works, the number of columns is not dynamic.

    0 讨论(0)
  • 2021-02-04 20:20

    Seb's answer put me onto the right track for a workaround. I am using Oracle and it has functions which emulate MYSQL's group_concat. Here is an example. This does not generate columns, and thus isn't as good as a pure SQL solution, but it is suitable for my current purposes.

    with data as
    ( 
      select 
        pc.id cat,
        p.id prod, 
        row_number() over( partition by p.id order by pc.id) rn,
        count(*) over (partition by p.id) cnt
      from product_to_category pc, product p
      where pc.product_id = p.id
    )
    select prod, ltrim(sys_connect_by_path(cat, ','), ',') cats
      from data
     where rn = cnt
     start with rn = 1 connect by prior prod = prod and prior rn = rn - 1
     order by prod
    

    This generates data such as

    PROD | CATS
    ===========
    284  |   12
    285  |   12
    286  | 9,12
    

    I can edit the ltrim(sys_connect_by_path()) column as needed to generate whatever data I need.

    0 讨论(0)
  • 2021-02-04 20:21

    You can't create these results with a strict SQL query. What you're trying to produce is called a pivot table. Many reporting tools support this sort of behavior, where you would select your product and category, then turn the category into the pivot column.

    I believe SQL Server Analysis Services supports functionality like this, too, but I don't have any experience with SSAS.

    0 讨论(0)
提交回复
热议问题