MySQL订购加入结果

时间:2013-11-08 21:37:39

标签: mysql sql join group-by

我不明白为什么这个查询没有按预期工作。我有一张马桌和文件桌。文件表有“fk_object”和“fk_id”列,所以我可以得到像fk_object =“horse_photo”和fk_id = 725这样的记录。文件表还有is_default和position列,因此我可以获取应该是其个人资料图片的文件(照片)。但是,我没有收到默认照片甚至第一个位置文件。有人可以向我解释为什么这个查询不能按预期工作,以及适当的解决方案是什么?谢谢!

SELECT `horse`.`id`,
       `horse`.`name`,
       `file`.`id` AS `fid`,
       `file`.`is_default`,
       `file`.`position`
FROM `horse`
LEFT OUTER JOIN `file` ON (`file`.`fk_id`=`horse`.`id`
                           AND `file`.`fk_object`="horse_photo")
GROUP BY `horse`.`id`
ORDER BY `horse`.`id` ASC,
         `file`.`is_default` DESC,
         `file`.`position` ASC;

要清楚,我想检索所有马匹及其默认照片(如果有的话)。

更多详情: File.is_default是一个0或1的布尔值.File.position是从0开始的UNSIGNED INT。加入的文件首先应该是is_default = 1,然后解析为File.position = 0(或最小的int)。

我得到的结果: 按Horse.id ASC排序的列表,但加入的文件似乎只是第一个文件(按主要id列排序)。

3 个答案:

答案 0 :(得分:0)

您的问题是您按马匹分组,但没有在您选择的其他列上使用任何聚合函数,如果您在一列上分组,则您选择的每个其他列必须是总和,或者最大值或分钟,这应该有效:

SELECT `horse`.`id`, `horse`.`name`, `file`.`id` AS `fid`, `file`.`is_default`, `file`.`position`
FROM `horse`
LEFT OUTER JOIN `file` ON (`file`.`fk_id`=`horse`.`id` AND `file`.`fk_object`="horse_photo")
GROUP BY `horse`.`id`, `horse`.`name`, `file`.`id` AS `fid`, `file`.`is_default`, `file`.`position`
ORDER BY `horse`.`id` ASC, `file`.`is_default` DESC, `file`.`position` ASC;

答案 1 :(得分:0)

如果我理解您的问题和您当前的结果,那么问题是您没有指定File.is_Default = 1。这与你通过Horse.id进行分组这一事实相结合,每匹马都会给你一行,而不管它首先找到哪一张照片。

如果您将“file.is_default = 1”添加到您的加入条件或新的Where子句,那么您应该获得所需的结果。如果将“file.is_default = 1”放在连接条件中并且没有默认照片,则任何文件列都将返回该匹配的空值。如果在Where子句中放入“file.is_default = 1”,则没有默认照片的马将不会出现在结果集中。

此外,为了让人们更容易阅读您的代码,我建议您对表格进行别名处理,并可能缩进代码,而不是将每个子句的所有内容放在一行上。

答案 2 :(得分:0)

要在我的第一个回答的评论中回答您的问题,不,您不能订购加入中使用的任何内容。您无法使用限制性命令对视图,内联函数,派生表,CTE或子查询进行排序。

所以,让我再试一次。您想要一个每匹马返回一条记录的查询。如果有默认照片,请返回该照片。如果没有默认值,则返回位置编号最小的那个。现在,我是CTE的忠实粉丝,正如您将在下面看到的那样。如果您是CTE的新手,这可能会令人困惑,但是一旦掌握了它们,它们就会让您的生活变得更加轻松!

第一个CTE(即Default_Photo)将为每匹马带回存在的任何默认照片上的数据。如果没有默认照片,则该马没有记录。

第二个CTE(即Next_Best_Photos)将为每匹马带回一行,其中最小位置编号不是默认值。这将包含非默认照片,即使对于有默认照片的马也是如此。这就是它应该采用的方式。

第三个CTE(即Final_Dataset)将为每匹马带回一个不同的行。如果那匹马缺少Default_Photos CTE中的相应行(即,它没有默认照片),那么它将显示与具有最小位置的照片相关联的信息。

您需要第三个查询的原因是,在t-sql(我使用的是)中,当您使用distinct命令时,它不允许您按派生列进行排序。

With Default_Photos as (
Select H.ID
    , F.ID as 'FID'
    , F.Position

From Horse H
    Inner Join File F
        on H.ID = F.ID

Where F.is_default = 1
)

, Next_Best_Photo as (
Select H.ID
    , F.ID as 'FID'
    , Min(F.Position) as Min_Position

From Horse H
    Inner Join File F
        on H.ID = F.ID

Where F.is_default = 0

Group by H.ID
    , F.ID
)

, Final_Dataset as (
Select Distinct H.ID
    , H.name
    , F.ID as 'FID'
    , Case
        When DP.ID is null
            Then 1
            Else 0
        End as is_default
    , Case
        When DP.ID is null
            Then F2.Position
            Else DP.Position
        End as position

From Horse H
    Inner Join File F
        on H.ID = F.ID
    Left Outer Join Default_Photos DP
        on H.ID = DP.ID
    Left Outer Join Next_Best_Photo NBP
        on H.ID = NBP.ID
    Left Outer Join File F2
        on NBP.FID = F2.ID
            and NBP.Min_Position = F2.Position
)

Select *

From Final_Dataset

Order by id asc
    , is_default desc
    , position asc

可能有一种更简单的方法可以做到这一点,但这就是我为我的仪表板构建数据集的方式,我需要绝对确定每个ID只能获得一行。