Расширенный SQL-запрос с большим количеством объединений - PullRequest
3 голосов
/ 09 июня 2010

Я занимаюсь расширенным поиском велосипедов.У меня есть много столов, к которым мне нужно присоединиться, чтобы найти все, скажем, красные и коричневые велосипеды.Один велосипед может быть более одного цвета!Я сделал этот запрос на данный момент:

SELECT DISTINCT p.products_id,                    #simple product id
                products_name,                    #product name
                products_attributes_id,           #color id
                pov.products_options_values_name  #color name
FROM   products p
       LEFT JOIN products_description pd
         ON p.products_id = pd.products_id
       INNER JOIN products_attributes pa
         ON pa.products_id = p.products_id
       LEFT JOIN products_options_values pov
         ON pov.products_options_values_id = pa.options_values_id
       LEFT JOIN products_options_search pos
         ON pov.products_options_values_id = pos.products_options_values_id
WHERE  pos.products_options_search_id = 4         #code for red
       OR pos.products_options_search_id = 5      #code for brown

Моя первая проблема - это множество соединений.Таблица Products в основном содержит идентификатор продукта и его изображение, а таблица Products Description содержит более описательную информацию, такую ​​как имя (и, конечно, идентификатор продукта).

Тогда у меня есть таблица Products Options Values, которая содержит всецвета и их идентификаторы.Products Options Search содержит идентификаторы цвета вместе с идентификатором группы цветов (products_options_search_id).Красный имеет код группы цветов 4 (коричневый - 5).

Продукты и цвета имеют отношение многих ко многим, управляемое внутри Products Attributes.

Так что мой вопрос в первую очередь: Можно ли делать так много объединений?Я ухудшаю производительность?

Второе: если велосипед будет красного и коричневого цвета, он появится дважды, хотя я использую SELECT DISTINCT.Думаю, это из-за INNER JOIN.Можно ли этого избежать, и нужно ли мне удалять двойные числа в моем PHP-коде?

Третье: велосипеды могут быть двухцветными (т.е. черным и синим).Это означает, что есть два ряда для этого велосипеда.Тот, где написано, что цвет черный, а другой - синий.(См. Второй вопрос).Но если я заменю OR в предложении WHERE, он удалит обе строки, потому что ни одна из них не удовлетворяет условиям - только продукт.Какой обходной путь для этого?

Ответы [ 4 ]

4 голосов
/ 09 июня 2010

Хорошо, во-первых, SQL сделан для объединения, и ваш запрос не очень большой. При правильной индексации это на самом деле должно повысить вашу производительность, поскольку легче получить правильные данные.

Вы можете удалить дубликаты, которые вы получаете, используя подзапрос следующим образом:

SELECT DISTINCT p.products_id,                    #simple product id
                products_name,                    #product name
                products_attributes_id,           #color id
                pov.products_options_values_name  #color name
FROM   products p
       LEFT JOIN products_description pd
         ON p.products_id = pd.products_id
WHERE p.products_id in (
       Select products_id from products_attributes pa #This will give you the ID forall bikes that have either red or brown in them
       INNER JOIN products_options_values pov
         ON pov.products_options_values_id = pa.options_values_id
       INNER JOIN products_options_search pos
         ON pov.products_options_values_id = pos.products_options_values_id
       WHERE  pos.products_options_search_id = 4         #code for red
            OR pos.products_options_search_id = 5      #code for brown)

Конечно, вы не сможете вернуть цвет как часть результатов, так как цвет не имеет единственного значения. Вы можете объединить цвета в одно поле, написав функцию, если вам нужно это сделать.

Ваш вариант на третьем состоит в том, чтобы либо свернуть данные в вашем PHP-коде (возвращать элементы более одного раза в наборе результатов, но циклически проходить и показывать каждый элемент только один раз), а затем отображать список возвращенных цветов другим способом (в качестве дополнительной таблицы или списка, разделенного запятыми, или того, что вам подходит.

Если вы сделаете ИЛИ И И это, конечно, означает, что все велосипеды будут красного и коричневого цвета. Это было бы правильно, если это то, что вы ищете, но звучит так, как будто вы хотите, а не оба.

2 голосов
/ 09 июня 2010

Это не много объединений. При условии достойных показателей это ни на что не повлияет отрицательно.

distinct выбирает отличную комбинацию всех полей в предложении select. Так что, да, если у вас более одного цвета, появится больше одного велосипеда, так как вы включили цветовое поле. Если вам нужен только один цвет, вы должны указать ему, какой цвет вы хотите (например, тот, который имеет максимальный код или что-то еще). Или не выбирайте цветовой код (поскольку вам все равно не важно, что это на самом деле). Хорошее правило: выбирайте только те поля, которые вам действительно нужны.

Ваш последний вопрос неясен. Если вы замените or чем? Если вы попытаетесь сделать это and нет, это не сработает, потому что ни в одной строке нет обоих кодов цвета (поскольку это невозможно).

1 голос
/ 09 июня 2010

Определенно не слишком много объединений.Если только предложение ON не является равенством, объединения, как правило, хорошо ограничивают результирующий набор, особенно когда доступны правильные индексы.

То, что вы хотите, похоже на поиск вопросов в SO по крайней мере с одним из спискатеги, поэтому я написал этот запрос в качестве сравнения: https://data.stackexchange.com/stackoverflow/query/2695/so3005416-comparison-select-questions-with-any-selected-tags

Игнорировать код, чтобы получить теги во временную таблицу, это просто подтверждение кода из ответа другого вопроса .Просто сравните два последних утверждения Select.

0 голосов
/ 09 июня 2010

Как указали Донни и Кобусве, это не так уж много объединений. Однако в реляционной (то есть нормализованной) схеме атрибуты товара (например, имя и цвет) обычно хранятся в таблице товаров, а не в отдельных таблицах.

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

SELECT p.products_id,                          #simple product id
       products_name,                          #product name
       min(products_attributes_id),            #lowest color ID
       max(products_attributes_id),            #highest color ID
       min(pov.products_options_values_name),  #lowest color name
       max(pov.products_options_values_name)   #highest color name
FROM   products p
       LEFT JOIN products_description pd
         ON p.products_id = pd.products_id
       INNER JOIN products_attributes pa
         ON pa.products_id = p.products_id
       INNER JOIN products_options_values pov
         ON pov.products_options_values_id = pa.options_values_id
       INNER JOIN products_options_search pos
         ON (pov.products_options_values_id = pos.products_options_values_id AND
        pos.products_options_search_id IN (4, 5) )         #codes for red, brown
group by p.products_id, products_name

В зависимости от того, какой диалект SQL (SQLServer, Oracle, MySQL и т. Д.) Вы используете, возможно, что синтаксис для конечного условия может немного отличаться.

Очевидно, что при возвращении только одного цвета самые низкие и самые высокие значения будут одинаковыми.

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