SQL для объединения одной таблицы в другую таблицу несколько раз? (Отображение продуктов по категориям) - PullRequest
5 голосов
/ 20 апреля 2009

Допустим, у меня есть таблицы Product, Category и Product_To_Category. Товар может быть нескольких категорий.

    Product                     Category        Product_to_category
    ID   |   NAME               ID  | Name      Prod_id | Cat_id
    =====================       ============    ===================
        1| Rose                    1| Flowers          1| 1
        2| Chocolate Bar           2| Food             2| 2
        3| Chocolate Flower                            3| 1
                                                       3| 2

Я хотел бы запрос SQL, который дает мне такой результат, как

    ProductName      | Category_1 | Category_2 | Category_3
    =======================================================
    Rose             | Flowers    |            |
    Chocolate Flower | Flowers    | Food       |

и т.д.

Лучший способ добиться этого - объединить несколько запросов; один запрос для каждого ожидаемого количества категорий для данного продукта.

select p.name, cat1.name, cat2.name
from
  product p, 
  (select * from category c, producttocategory pc where pc.category_id = c.id) cat1,
  (select * from category c, producttocategory pc where pc.category_id = c.id) cat2
where p.id = cat1.id 
  and p.id = cat2.id
  and cat1.id != cat2.id
union all
select p.name, cat1.name, null
from
  product p, 
  (select * from category c, producttocategory pc where pc.category_id = c.id) cat1
where p.id = cat1.id 
  and not exists (select 1 from producttocategory pc where pc.product_id = p.id and pc.category_id != cat1.id)

Есть несколько проблем с этим.

  • Во-первых, я должен повторить этот союз для каждой ожидаемой категории; если товар может быть в 8 категориях, мне нужно 8 запросов.
  • Во-вторых, категории не помещаются в одинаковые столбцы одинаково. Например, иногда продукт может иметь «Еда, Цветы», а другой раз «Цветы, Еда».

Кто-нибудь знает лучший способ сделать это? Кроме того, у этой техники есть техническое название?

Ответы [ 4 ]

9 голосов
/ 20 апреля 2009

Я не знаю, какую СУБД вы используете, но в MySQL вы можете использовать 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
1 голос
/ 20 апреля 2009

Ответ Себа поставил меня на правильный путь для обхода. Я использую Oracle, и у него есть функции, которые имитируют MYSQL group_concat. Вот пример. Это не генерирует столбцы и, следовательно, не так хорошо, как решение на чистом SQL, но подходит для моих текущих целей.

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

Это генерирует данные, такие как

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

Я могу редактировать столбец ltrim (sys_connect_by_path ()) по мере необходимости, чтобы генерировать любые данные, которые мне нужны.

1 голос
/ 20 апреля 2009
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'

Это работает только если вы знаете количество возможных категорий, чтобы поместить их в столбцы. Вот так (стандартный) SQL работает, число столбцов не является динамическим.

1 голос
/ 20 апреля 2009

Вы не можете создать эти результаты с помощью строгого запроса SQL. То, что вы пытаетесь создать, называется сводная таблица . Многие инструменты отчетности поддерживают такое поведение, когда вы выбираете свой продукт и категорию, а затем превращаете категорию в сводный столбец.

Я полагаю, что службы анализа SQL Server также поддерживают такую ​​функциональность, но у меня нет опыта работы с SSAS.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...