具有大量连接的高级SQL查询

时间:2010-06-09 11:39:11

标签: sql search join

我正在开发一种先进的自行车搜索方式。我有很多桌子需要加入才能找到所有,比方说,红色和棕色自行车。一辆自行车可能会有多种颜色!我现在已经提出了这个问题:

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,则会删除这两行,因为它们都不符合条件 - 只有产品。解决方法是什么?

4 个答案:

答案 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等),最终条件的语法可能需要略有不同。

显然,只返回一种颜色,最低和最高值将相同。