与INNER JOIN的DISTINCT

时间:2012-06-21 08:48:52

标签: sql

我有一个问题要求

餐桌水果

 FruitID |  Fruit  | Unit Price 
    1    |  Orange |     $3
    2    |  Apple  |     $2
    3    |  Grape  |     $4

表FruitDetails

Picture      | Color   | FruitID
Orange_o.jpg | Orange  |    1
Apple_g.jpg  | Green   |    2
Apple_r.jpg  | Red     |    2
Grape_p.jpg  | Purple  |    3
Grape_g.jpg  | Green   |    3

我想得到的结果是没有重复名字的所有成果。

实施例

Fruit | UnitPrice | Picture      | Color
Orange|    $3     | Orange_o.jpg | Orange
Apple |    $2     | Apple_g.jpg  | Green
Grape |    $4     | Grape_p.jpg  | Purple

这有可能实现吗? 感谢

2 个答案:

答案 0 :(得分:1)

为SQL Server编写,但实际查询应该适用于其他数据库。

设置数据:

declare @Fruit table (FruitID int not null,Fruit varchar(10) not null,UnitPrice int not null)
insert into @Fruit(FruitID,Fruit,UnitPrice) values
(1,'Orange',3),
(2,'Apple',2),
(3,'Grape',4)

declare @FruitDetails table (FruitID int not null,Picture varchar(20) not null,Color varchar(10) not null)
insert into @FruitDetails (FruitID,Picture,Color) values
(1,'Orange_o.jpg','Orange'),
(3,'Grape_p.jpg','Purple'),
(3,'Grape_g.jpg','Green'),
(2,'Apple_g.jpg','Green'),
(2,'Apple_r.jpg','Red')

查询:

select
    f.Fruit,
    f.UnitPrice,
    fd.Picture,
    fd.Color
from
    @Fruit f
        inner join
    @FruitDetails fd
        on
            f.FruitID = fd.FruitID
        left join
    @FruitDetails fd_anti
        on
            f.FruitID = fd_anti.FruitID and
            fd_anti.Picture < fd.Picture --This is the condition for picking a better row
where
    fd_anti.FruitID is null --This eliminates rows where a better row was picked

结果:

Fruit      UnitPrice   Picture              Color
---------- ----------- -------------------- ----------
Orange     3           Orange_o.jpg         Orange
Grape      4           Grape_g.jpg          Green
Apple      2           Apple_g.jpg          Green

哪个与您的预期结果不符,但您没有给我们一个关于从FruitDetail选择“最佳”行的条件的良好定义。

答案 1 :(得分:1)

SQL中没有“挑选任何一个”。这不是有充分理由的;它不会是确定性的,这会让你很头疼试图调试你的应用程序。然而,可以手动选择一个,它只需要一些额外的技巧(一些数据库有扩展,可以使它更容易,但谈到通用SQL)。

首先,您必须选择一个标准来选择要加入的一行。假设您希望首先按字母顺序排列颜色(在实际情况下,您可能具有某些优先级或重要性)。您使用的列对于每个水果必须是唯一的!您可以通过group-by或嵌套select的另一个连接来计算它。嵌套选择是IMO更容易编写和理解。它将是:

(select min(Color) from FruitDetails as inner where inner.Fruit = Fruit.Fruit)

现在你加入带有条件的表,颜色就是那个,所以:

select * from Fruit
    join FruitDetails as outer
        on outer.Fruit = Fruit.Fruit
        and outer.Color = (select min(Color) from FruitDetails as inner where inner.Fruit = Fruit.Fruit)

这假设FruitDetails表中有一个Fruit列,您忘了,但如果没有该列,则根本无法进行连接。并且它有一个unique(Fruit, Color)约束,以保证每个水果只有一行具有最小颜色值。

另外两个连接的替​​代方案是:

select Fruit.* ThisDetails.*
    from Fruit
    join FruitDetails as ThisDetails using (Fruit)
    join FruitDetails as BestDetails using (Fruit)
    group by Fruit.*, ThisDetails.*
    having ThisDetails.Color = min(BestDetails.Color)

using (column)onetable.column = othertable.column的缩写,在大多数但不是全部的SQL变体中)