MYSQL-запрос по товарам в диапазоне ценовых вариантов без дубликатов - PullRequest
0 голосов
/ 14 января 2019

Я пытаюсь сделать запрос к моей таблице продуктов так, чтобы мой запрос возвращал набор продуктов в пределах определенного ценового диапазона вариантов - у продуктов есть много вариантов, и варианты принадлежат продуктам. У меня есть следующий запрос, который работает, но он очень медленный - запрос занимает 1,66 секунды.

SELECT colortags.tag, products.*, (SELECT variants.price FROM variants WHERE variants.product_id = products.product_id LIMIT 1) price, collects.position 
FROM products
INNER JOIN wp_wps_collects collects 
ON products.product_id = collects.product_id 
AND collects.collection_id = 123456788
INNER JOIN wp_wps_tags colortags 
ON colortags.product_id = collects.product_id 
AND (colortags.tag = 'black' OR colortags.tag = 'nav') 
INNER JOIN wp_wps_tags styletags 
ON styletags.product_id = collects.product_id 
AND (styletags.tag = 'purses')
WHERE (SELECT variants.price FROM variants WHERE variants.product_id = products.product_id AND variants.price >= 200 AND variants.price < 300 LIMIT 1) > 0
AND (SELECT variants.price FROM variants WHERE variants.product_id = products.product_id AND variants.price >= 200 AND variants.price < 300 LIMIT 1) <> 0

В операторе WHERE я попытался просто проверить значение price, созданное моим подзапросом в моем операторе SELECT, но MYSQL сообщает мне, что price не определено. Вот SQL:

SELECT colortags.tag, products.*, (SELECT variants.price FROM wp_wps_variants variants WHERE variants.product_id = products.product_id LIMIT 1) price, collects.position 
FROM wp_wps_products products
INNER JOIN wp_wps_collects collects 
ON products.product_id = collects.product_id 
AND collects.collection_id = 98515058801
INNER JOIN wp_wps_tags colortags 
ON colortags.product_id = collects.product_id 
AND (colortags.tag = 'color:generic-black' OR colortags.tag = 'color:navy') 
INNER JOIN wp_wps_tags styletags 
ON styletags.product_id = collects.product_id 
AND (styletags.tag = 'style:totes')
WHERE price >= 200 
AND price < 300

Это сообщение об ошибке, полученное сразу после SQL:

Неизвестный столбец «цена» в «где пункт»

Я также пытался использовать серию объединений в таблице variants, но затем мне возвращаются дубликаты продуктов. Вот SQL

SELECT colortags.tag, products.*, (SELECT variants.price FROM variants WHERE variants.product_id = products.product_id LIMIT 1) price, collects.position 
FROM products
INNER JOIN collects 
ON products.product_id = collects.product_id 
AND collects.collection_id = 1234566
INNER JOIN colortags 
ON colortags.product_id = collects.product_id 
AND (colortags.tag = 'black' OR colortags.tag = 'navy') 
INNER JOIN styletags 
ON styletags.product_id = collects.product_id 
AND (styletags.tag = 'purses')
INNER JOIN variants
ON variants.product_id = products.product_id
AND variants.price >= 200 
AND variants.price < 300
AND variants.price > 0
AND variants.price <> 0

Мне хотелось бы получить результаты запроса, полученные из первого оператора SQL без снижения производительности. Я хотел бы думать, что я могу написать SQL с INNER JOIN в таблице вариантов, чтобы отфильтровать варианты с неправильной ценой, не получая дубликаты продуктов, но я не могу определить, как.

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

Ответы [ 2 ]

0 голосов
/ 14 января 2019

Вы делаете полусоединение , что означает, что вы хотите выполнить объединение, но вам нужен только один ряд результатов, даже если есть несколько совпадений.

Один из способов сделать это - присоединиться к производной таблице, которая использует GROUP BY в подзапросе, чтобы уменьшить количество вариантов до одной строки на product_id.

SELECT colortags.tag, products.*, prices.price, collects.position 
FROM products
INNER JOIN wp_wps_collects collects 
  ON products.product_id = collects.product_id 
  AND collects.collection_id = 123456788
INNER JOIN wp_wps_tags colortags 
  ON colortags.product_id = collects.product_id 
  AND (colortags.tag = 'black' OR colortags.tag = 'nav') 
INNER JOIN wp_wps_tags styletags 
  ON styletags.product_id = collects.product_id 
  AND (styletags.tag = 'purses')
INNER JOIN (
  SELECT v.product_id, MIN(v.price) AS price FROM variants v
  INNER JOIN wp_wps_collects c ON v.product_id = c.product_id
  WHERE c.collection_id = 123456788
  GROUP BY product_id ORDER BY NULL
) prices
  ON products.product_id = prices.product_id

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

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

0 голосов
/ 14 января 2019

Если вы инкапсулируете свой запрос в другой, вы можете использовать price в where предложении

SELECT * from (
    SELECT colortags.tag, products.*, (SELECT variants.price FROM variants WHERE variants.product_id = products.product_id LIMIT 1) price, collects.position 
    FROM products
    INNER JOIN wp_wps_collects collects 
    ON products.product_id = collects.product_id 
    AND collects.collection_id = 123456788
    INNER JOIN wp_wps_tags colortags 
    ON colortags.product_id = collects.product_id 
    AND (colortags.tag = 'black' OR colortags.tag = 'nav') 
    INNER JOIN wp_wps_tags styletags 
    ON styletags.product_id = collects.product_id 
    AND (styletags.tag = 'purses')
    WHERE (SELECT variants.price FROM variants WHERE variants.product_id = products.product_id AND variants.price >= 200 AND variants.price < 300 LIMIT 1) > 0
) t 
WHERE t.price >= 200 and t.price < 300 
...