我如何有选择地加入

时间:2016-06-15 08:14:16

标签: mysql sql join

假设我有一张车辆表:

v            color      col3       col4    col5   .....
car          red
train        gray
plane        white
car          blue
bike         black
(1000 more)

包含分类的表格:

prio     v        color         class
1        car      red           C1
2        car      %             F3
3        plane    %             W1
4        bike     blue          B4
5        bike     white         B8
6        bike     %             O9

分类表很小,小于100.只有一个查找表。如有必要,我们可以向车辆添加id列。

现在我想将分类添加到车辆表中。车辆中的行数不得更改。 结果应该是:

v            color   class
car          red     C1
train        gray
plane        white   W1
car          blue    F3
bike         black   O9
(1000 more)

现在,如果我这样做

SELECT vehicles v
LEFT JOIN classifications c ON v.v LIKE c.v AND v.color LIKE c.color

我得到重复的条目,因为分类匹配不是唯一的。例如,白色自行车匹配规则5和6,在这种情况下,必须采用规则5,因为它具有较低的prio

如何避免重复?

5 个答案:

答案 0 :(得分:3)

您可以使用相关查询和LIMIT

执行此操作
SELECT v.*,
       (SELECT c.class FROM classifications c
        WHERE v.v like c.v AND v.color LIKE c.color
        ORDER BY c.prio LIMIT 1) AS class
FROM vehicles v

虽然我不明白你为什么要使用LIKE如果你正在寻找完全匹配,我认为这会更快:

c.color IN(v.color,'%')

LIKE用于部分字符串比较,它是一个真正的性能杀手!所以尽量避免使用它。

答案 1 :(得分:0)

不同怎么样?

select distinct vehicles v left join classifications c
on v.v like c.v and v.color like c.color

我现在无法尝试,但这应该足以满足您的要求......

答案 2 :(得分:0)

编辑:此查询无效,如下面的评论中所述。无论如何,我会留下这个答案用于学习目的。

您可以使用汇总函数group by, havingmin函数

来实现
select * from vehicles v 
            left join classifications c on v.v like c.v and v.color like c.color 
            group by v.v
            having MIN(prio)

这将按车辆分组结果,然后选择优先级最低的行。

答案 3 :(得分:0)

SELECT * FROM vehicles v LEFT JOIN classifications c ON c.prio= (SELECT prio FROM classifications c WHERE v.v like c.v AND v.color LIKE c.color ORDER BY c.prio LIMIT 1) 这假定“prio”是唯一的。

答案 4 :(得分:0)

如果你想避免使用相关的子查询(这取决于数据可能会导致性能问题,因为它需要MySQL为每个返回的行执行子查询),那么还有其他几个选项: - < / p>

有一个子查询,为每个车辆/颜色带回最小prio(所以这个子查询执行一次),并将其加入车辆,颜色和最小值匹配的分类表

SELECT v.v,            
    v.color,      
    c.class 
FROM vehicles v
LEFT OUTER JOIN
(
    SELECT v, color, MIN(prio) AS min_prio
    FROM classifications
    GROUP BY v, color
) sub0
ON v.v = sub0.v AND v.color = sub0.color
LEFT JOIN classifications c ON sub0.v = c.v AND sub0.color = c.color AND sub0.min_prio = c.prio

另一种选择是滥用GROUP_CONCAT功能。这确实假设类字段不包含任何逗号(如果它可能那么你可以使用另一个分隔符)。

SELECT v.v,            
    v.color,      
    SUBSTRING_INDEX(GROUP_CONCAT(c.class ORDER BY prio), ',', 1) AS class
FROM vehicles v
LEFT JOIN classifications c ON v.v = c.v AND v.color = c.color
GROUP BY v.v,            
    v.color