【问题标题】:Getting different SQL results when I feel like it should be the same当我觉得应该相同时得到不同的 SQL 结果
【发布时间】:2015-07-02 16:05:00
【问题描述】:

所以我有一个我正在尝试运行的查询。现在它正在我的代码中运行一个循环,并对每个社区 ID 进行选择。我宁愿它只做一次选择,然后循环遍历这些结果,因为这对 DB imho 的影响要小得多。无论如何,我不明白为什么这两个查询给了我不同的结果:

第一个查询:

SELECT `neighbourhood_id`,
    SUM(IF(`c`.`listing_offer` = 1, 1, 0)) as `listing_for_sale`,
    AVG(IF(`c`.`listing_offer` = 1, `price`, 0)) as `avg_sale_price`,
    SUM(IF(`c`.`listing_offer` = 2, 1, 0)) as `listing_for_rent`,
    AVG(IF(`c`.`listing_offer` = 2, `price`, 0)) as `avg_rent_price`
FROM (
    SELECT `n`.`id` AS `neighbourhood_id`, `l`.*
    FROM `listing` `l`
        LEFT JOIN `address` `a` ON `l`.`address_id` = `a`.`id` 
        LEFT JOIN `address_neighbourhood` `an` ON `a`.`id` = `an`.`address_id` 
        LEFT JOIN `neighbourhood` `n` ON `an`.`neighbourhood_id` = `n`.`id` 
        WHERE (`l`.`deleted`=0) 
            AND `n`.`id` IS NOT NULL
            AND `n`.`id` = 1
        GROUP BY `l`.`id`
    ) `c`
GROUP BY `neighbourhood_id`

结果:

neighbourhood_id    listing_for_sale    avg_sale_price  listing_for_rent    avg_rent_price
1                   7541                486634.853967   4045                786.372706

第二次查询:

SELECT `neighbourhood_id`,
    SUM(IF(`c`.`listing_offer` = 1, 1, 0)) as `listing_for_sale`,
    AVG(IF(`c`.`listing_offer` = 1, `price`, 0)) as `avg_sale_price`,
    SUM(IF(`c`.`listing_offer` = 2, 1, 0)) as `listing_for_rent`,
    AVG(IF(`c`.`listing_offer` = 2, `price`, 0)) as `avg_rent_price`
FROM (
    SELECT `n`.`id` AS `neighbourhood_id`, `l`.*
    FROM `listing` `l`
        LEFT JOIN `address` `a` ON `l`.`address_id` = `a`.`id` 
        LEFT JOIN `address_neighbourhood` `an` ON `a`.`id` = `an`.`address_id` 
        LEFT JOIN `neighbourhood` `n` ON `an`.`neighbourhood_id` = `n`.`id` 
        WHERE (`l`.`deleted`=0) 
            AND `n`.`id` IS NOT NULL
        GROUP BY `l`.`id`
    ) `c`
WHERE `neighbourhood_id` = 1
GROUP BY `neighbourhood_id`

结果:

neighbourhood_id    listing_for_sale    avg_sale_price  listing_for_rent    avg_rent_price  
1                   5740                522544.830430   2870                762.646690

我很确定查询 1 是正确的结果,所以我不确定为什么我在第二个查询中得到不同的结果。尽管就哪一个是正确的而言,我仍然需要得到纠正。

非常感谢任何帮助。

【问题讨论】:

  • 第二种情况下的内部“GROUP BY”可能正在对具有 neighbourhood=1 和其他一些值的行进行分组,并在选择结果中返回其他值之一作为邻域。
  • 在第一个查询中是 "AND n.id IS NOT NULL" 因为子句的下一部分是 "AND nid = 1" 是互斥的
  • @PaulF IS NOT NULL 在那里,因为我想删除 `n.id=1` 并获取所有社区的结果。

标签: mysql sql tsql


【解决方案1】:

首先使用 group by 然后 where 条件是过滤记录集。现在的关键是没有必要按维护顺序分组。您的两个查询的子查询都以不同的顺序返回结果,然后为过滤器创建问题。

条件是ANDneighbourhood.id= 1在第一个查询中表单子查询'c'的where子句中,该条件在主查询的Where子句中。这意味着在第二个查询的子查询中 c 的记录集可以具有除 1 以外的 neighbourhood.id 值,并且在该组之后使用该组,该记录集的值可以是该记录集中的任何内容。但在第一个子查询中,仅选择neighbourhood.id=1e 的那些记录集,并按结果分组一个可以具有value neighbourhood.id=1 的记录。

例如 您的第二个查询的子查询 c 选择了带有 n.id = 0 的记录,但是该记录将被拒​​绝并且不会用于外部查询,因为 n.id=1 正在测试,因此不使用内部查询结果。但是在第一个查询的子查询中 c 将选择那些 n.id=1 的记录,并且它总是在外部查询中使用。因此,两种结果不同。

假设子查询 c 是 -

SELECT `l`.`id` , `n`.id
    FROM `listing` `l`
        LEFT JOIN `address` `a` ON `l`.`address_id` = `a`.`id` 
        LEFT JOIN `address_neighbourhood` `an` ON `a`.`id` = `an`.`address_id` 
        LEFT JOIN `neighbourhood` `n` ON `an`.`neighbourhood_id` = `n`.`id` 
        WHERE (`l`.`deleted`=0) 
            AND `n`.`id` IS NOT NULL;

是结果-

(l.id , n.id) (1,0),(1,1)

当使用 group by 时,它会返回-

(l.id , n.id) (1,0) 

并且这条记录不用于外部查询。

但在第一次查询中,子查询的结果是

(l.id , n.id) (1,1) 

它用于外部查询。

【讨论】:

  • 我还是不太明白。在第一个查询中,内部查询只选择n.id = 1 的记录,因此外部查询没有丢弃任何内容。对于第二个查询,它会选择所有记录,但外部查询随后会丢弃所有不是n.id = 1 的记录。在我看来,这是一样的,第一个它在内部查询中过滤/丢弃,第二个它在外部查询中执行。我想我在这里误解了一些基本原理
  • @SynackSA 我已经设置了示例
  • 您的评论让我回过头来查看我的数据以及为什么该语句按l.id 分组。我的address_neighbourhood 表有很多重复数据。我修复了表格和数据,这让我的生活变得轻松了很多,以至于我现在可以在一个查询中完成我想做的事情。谢谢
【解决方案2】:

答案是你试图一次做太多事情。您不希望通过列表 ID 进行分组(我认为您不会这样做,如果是这样,您需要在最里面的查询中使用聚合)。我相信这是你真正需要的(注意聚合都是 SUM):

select `neighbourhood_id`, 
    `listing_for_sale`, `total_sale_price` / `listing_for_sale` as `avg_sale_price`,
    `listing_for_rent`, `total_rent_price` / `listing_for_rent` as `avg_rent_price` from
    (SELECT `neighbourhood_id`,
        SUM(IF(`c`.`listing_offer` = 1, 1, 0)) as `listing_for_sale`,
        SUM(IF(`c`.`listing_offer` = 1, `price`, 0)) as `total_sale_price`,
        SUM(IF(`c`.`listing_offer` = 2, 1, 0)) as `listing_for_rent`,
        SUM(IF(`c`.`listing_offer` = 2, `price`, 0)) as `total_rent_price`
    FROM (
        SELECT `n`.`id` AS `neighbourhood_id`, `l`.*
        FROM `listing` `l`
         LEFT JOIN `address` `a` ON `l`.`address_id` = `a`.`id` 
         LEFT JOIN `address_neighbourhood` `an` ON `a`.`id` = `an`.`address_id` 
         LEFT JOIN `neighbourhood` `n` ON `an`.`neighbourhood_id` =        `n`.`id` 
        WHERE (`l`.`deleted`=0) 
         AND `n`.`id` IS NOT NULL
    ) `c`
  GROUP BY `neighbourhood_id`
) `d`

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-15
    • 2021-04-11
    • 1970-01-01
    • 1970-01-01
    • 2019-01-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多