2015-01-12 4 views
0

я есть рекурсивный таблицу категории и таблицу компании с полями, как:SQL оптимизации с анти присоединиться

category(id, name, parent) // parent is foreign key to category id :) 
company(id, category_1, category_2, category_3) // category_* is foreign key to category id 

категория дерево на глубине макс = 3;

категории ой -> категория су -> категория CZ

со знанием категорий компании всегда связанно с последней категорией (с3), я хочу все категории, что компания связана с (c1z, c2Z, c3z, c1y, c2y, c3y, c1x, c2x, c3x) для моей поисковой системы. // c1y является родителем category_1 и C1x является родителем родителя категории 1 ...

лучший запрос я придумал это:

SELECT 
    ID, 
    NAME 
FROM category c3 
WHERE ID IN (
    select category_1 from company where id=:companyId 
    union 
    select category_2 from company where id=:companyId 
    union 
    select category_3 from company where id=:companyId 
    union 
     select parent from category where id in (
      select category_1 from company where id=:companyId 
      union 
      select category_2 from company where id=:companyId 
      union 
      select category_3 from company where id=:companyId 
     ) 
    union 
     select parent from category where id in (
      select parent from category where id in (
      select category_1 from company where id=:companyId 
      union 
      select category_2 from company where id=:companyId 
      union 
      select category_3 from company where id=:companyId 
     ) 
     ) 
) 

имеет столько дубликат в нем. один для категории_ * в компании. и один для повторения его несколько раз.

любой способ удалить все дубликаты?

--update--

Предположим, мы решаем category- * поля с помощью двух таблиц насчет рекурсивного проблемы с 3 уровнями категории?

, например, если имеется только одна категория, это будет выглядеть как

SELECT 
    ID, 
    NAME 
FROM category 
WHERE ID IN (
    select category_1 from company where id=:companyId 
    union 
    select parent from category where id in (
    select category_1 from company where id=:companyId 
) 
    union 
    select parent from category where id in (
    select parent from category where id in (
     select category_1 from company where id=:companyId 
    ) 
) 
); 
+0

Какая СУБД вы используете? Postgres? Oracle? –

+0

SELECT DISTINCT ... –

+0

Я использую oracle, но я не хочу, чтобы он был связан с базой данных, поэтому его очень можно изменить в функции. – alizelzele

ответ

1

Если вы хотите присоединиться к данным, используя что-то вроде этого (например, сервер SQL):

DECLARE @category TABLE (id INT IDENTITY(1,1), name VARCHAR(30), parent INT) -- parent is foreign key to category id :) 
DECLARE @company TABLE (id INT IDENTITY(1,1), category_1 INT, category_2 INT, category_3 INT) --category_* is foreign key to category->id 


INSERT INTO @category (name, parent) 
VALUES('Top category', null), ('Cars', 1) 

INSERT INTO @company (category_1, category_2 , category_3) 
VALUES(2, null, null), (2, 2, null), (2, 2, 2) 


SELECT t1.*, t2.* 
FROM @category AS t1 INNER JOIN @company AS t2 ON t1.id = t2.category_1 or t1.id = t2.category_2 or t1.id = t2.category_3 

Приведенный выше код производит :

id name parent id category_1 category_2 category_3 
2 Cars 1 1 2 NULL NULL 
2 Cars 1 2 2 2 NULL 
2 Cars 1 3 2 2 2 

Но такая структура базы данных неверна!

Вместо одной таблицы

company(id, category_1, category_2, category_3) 

создать две таблицы

company(id, name) 
comp_cat(id, comp_id, cat_id) 

Почему? Я не хочу отвечать напрямую, поэтому я спрашиваю вас: 1) что происходит, когда компания связана с более чем тремя категориями? 2) зачем сохранять нули в случае, если вторая и третья категории не установлены?

В случае SQL Server, вы можете использовать Common Table Expressions:

;WITH CTE AS 
(
    SELECT id, category_1 AS cat_id 
    FROM @company 
    WHERE NOT category_1 IS NULL 
    UNION ALL 
    SELECT id, category_2 AS cat_id 
    FROM @company 
    WHERE NOT category_2 IS NULL 
    UNION ALL 
    SELECT id, category_3 AS cat_id 
    FROM @company 
    WHERE NOT category_3 IS NULL 
) 
SELECT DISTINCT t1.*, t2.* 
FROM CTE AS t1 INNER JOIN @category AS t2 ON t1.cat_id = t2.id 

Приветствия, Maciej

+0

Я знаю, что многие из этих категорий будут пустыми. и я подумал о переходе на 2 таблицы. никогда не должно быть более трех категорий. поэтому я подумал, что, возможно, таким образом он будет иметь лучшую производительность вместо использования 2 таблиц. – alizelzele

+0

@alizelzele. Как я уже упоминал, использование одной таблицы - плохая практика программирования, когда вы работаете с реляционной базой данных. –

+0

Я видел общие выражения таблицы, но я не хочу использовать какой-либо dbms Specefic grammer. – alizelzele

0

я использовал common table expressions для моего запроса. и это последний запрос, который я придумал:

with cte as (
    select category_1 as id from company where id=:companyId and category_1 is not null 
    union 
    select category_2 as id from company where id=:companyId and category_2 is not null 
    union 
    select category_3 as id from company where id=:companyId and category_3 is not null 
) select id, name FROM category WHERE id IN (
     select id from cte 
    union 
     select parent from category where id in (select id from cte) 
    union 
     select parent from category where id in (
     select parent from category where id in (select id from cte) 
    ) 
    ); 

Это лучший способ, о котором я мог думать. спасибо @Maciej за показ пути, и спасибо @Nicholai за информацию о поддержке СУБД.

Только в том случае, если существует способ транспонирования строки в столбец, такой как matlab do ...: P

+0

Можно преобразовать/перенести строки в столбцы и наоборот. См. Инструкции Pivot и Unpivot. –

Смежные вопросы