我正在开发一种先进的自行车搜索方式。我有很多桌子需要加入才能找到所有,比方说,红色和棕色自行车。一辆自行车可能会有多种颜色!我现在已经提出了这个问题:
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
表主要包含产品ID及其图像,Products Description
表包含更多描述性信息,例如名称(当然还有产品ID)。
然后我有Products Options Values
表,其中包含所有颜色及其ID。 Products Options Search
包含颜色ID以及颜色组ID(products_options_search_id)。红色的颜色组代码为4(棕色为5)。
产品和颜色在Products Attributes
内管理了多对多关系。
所以我的问题首先是:是否可以进行如此多的连接?我是否在伤害表演?
第二:如果一辆自行车有红色和棕色,即使我使用SELECT DISTINCT
,它也会出现两次。认为这是因为INNER JOIN
。这是否可以避免,我是否必须删除PHP代码中的双打?
第三:自行车可以是双色的(即黑色和蓝色)。这意味着该自行车有两排。其中一种颜色是黑色,一种颜色是蓝色。 (见第二个问题)。但是,如果我替换OR
子句中的WHERE
,则会删除这两行,因为它们都不符合条件 - 只有产品。解决方法是什么?
答案 0 :(得分:4)
好的,首先是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)
当然,由于颜色没有单一值,您将无法将颜色作为结果的一部分返回。如果需要,可以通过编写函数将颜色组合成单个字段。
您在第3个选项上的选项是汇总PHP代码中的数据(在结果集中多次返回项目,但循环显示并仅显示每个项目一次),然后显示返回的颜色列表以不同的方式(作为附加表格或逗号分隔列表或任何适合您的方式。
如果你使OR为AND它当然意味着所有的红色和棕色的自行车。如果这是你正在寻找的,这将是正确的,但它听起来像你想要的而不是两者。
答案 1 :(得分:2)
这不是很多连接。假设体面的指数不会对任何事情产生负面影响。
distinct
会选择select
子句中所有字段的不同组合。所以,是的,如果您有多种颜色,因为您已经包含了颜色字段,因此会显示多个自行车。如果你只想要一种颜色,你应该告诉它你想要哪种颜色(比如,具有最大代码的那种颜色,或者某种颜色)。或者不要选择颜色代码(因为你似乎并不关心它实际上是什么)。好的经验法则:只选择你真正需要的字段。
您的上一个问题尚不清楚。如果将or
替换为什么?如果你尝试使它and
没有它就行不通,因为没有一行有两个颜色代码(因为那是不可能的)。
答案 2 :(得分:1)
肯定没有太多的加入。除非ON
子句不相等,否则连接通常会很好地限制结果集,尤其是当正确的索引可用时。
你想要的是类似于使用至少一个标签列表在SO上查找问题,所以我将该查询作为比较编写:https://data.stackexchange.com/stackoverflow/query/2695/so3005416-comparison-select-questions-with-any-selected-tags
忽略代码以将标记放入临时表中,这实际上只是确认来自another question's answer的代码。只需比较两个最终的Select
语句。
答案 3 :(得分:0)
正如Donnie和Cobusve指出的那样,这并不是很多。但是,在关系(即标准化)模式中,产品属性(如名称和颜色)通常存储在产品表中,而不是存储在单独的表中。
假设您无法对表结构执行任何操作,则可能是以下替代查询:
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等),最终条件的语法可能需要略有不同。
显然,只返回一种颜色,最低和最高值将相同。