三个表的关系顺序正确,但值是错误的

时间:2019-07-16 22:32:13

标签: mysql sql left-join inner-join query-performance

我有那些桌子

     table1
|  id  |  name  |
|  1   |  axe   |
|  2   |  bow   |
|  3   |  car   |
|  4   |  dart  |


        table2                                        table3
|  t1_id  |  number  |                        |  t1_id  |  letter  |
|  1      |  5       |                        |  1      |  a       |
|  1      |  6       |                        |  1      |  b       |
|  1      |  2       |                        |  1      |  c       |
|  2      |  2       |                        |  2      |  a       |
|  2      |  2       |                        |  2      |  c       |
|  2      |  3       |                        |  2      |  r       |
|  3      |  8       |                        |  3      |  y       |
|  3      |  3       |                        |  3      |  i       |
|  3      |  1       |                        |  3      |  a       |
|  4      |  8       |                        |  4      |  a       |
|  4      |  9       |                        |  4      |  b       |
|  4      |  10      |                        |  4      |  c       |

table1(id)与table2(t1_id),table3(t1_id)链接

我运行它以按最高字母数匹配,然后按最高平均数匹配使它们排序,以获得此正确结果{{3 }}

SELECT 
  t1.id, 
  t1.name

FROM 
  table1 t1

INNER JOIN 
  table2 t2
    ON t2.t1_id = t1.id

LEFT JOIN 
  table3 t3
    ON t3.t1_id = t1.id
      AND t3.letter IN ('a', 'b', 'c')

GROUP BY
  t1.id

ORDER BY
  COUNT(t3.letter) DESC,
  AVG(t2.number) DESC

|  id  |  name  |
|  4   |  dart  |
|  1   |  axe   |
|  2   |  bow   |
|  3   |  car   |

一切都很好


但是当我想检查查询是否有问题时,我决定检查 letter_count avg_number ,因此我使用了该查询

SELECT 
  t1.id, 
  t1.name, 
  COUNT(t3.letter) AS letter_count, 
  AVG(t2.number) AS avg_number

FROM 
  table1 t1

INNER JOIN 
  table2 t2
    ON t2.t1_id = t1.id

LEFT JOIN 
  table3 t3
    ON t3.t1_id = t1.id
      AND t3.letter IN ('a', 'b', 'c')

GROUP BY
  t1.id

ORDER BY
  letter_count DESC,
  avg_number DESC

我期望的结果是

|  id  |  name  |  letter_count  |  avg_number   |
|  4   |  dart  |  3             |  9            |
|  1   |  axe   |  3             |  4.3333333333 |
|  2   |  bow   |  2             |  2.3333333333 |
|  3   |  car   |  1             |  4            |

但是我得到的结果是http://www.sqlfiddle.com/#!9/69086b/8/0

|  id  |  name  |  letter_count  |  avg_number   |
|  4   |  dart  |  9             |  9            |
|  1   |  axe   |  9             |  4.3333333333 |
|  2   |  bow   |  6             |  2.3333333333 |
|  3   |  car   |  3             |  4            |

令我惊讶的是 letter_count 的乘法行,可以通过派生查询来解决,但我不想选择 letter_count number_average 我只想订购他们

是否像使用 ORDER BY 一样保持查询只会影响查询性能,或者即使我不需要选择数据值(因为顺序正确),我是否仍应使用派生查询还是在大型表中派生查询会更快?

2 个答案:

答案 0 :(得分:1)

您真的在这里问了两个问题:

  1. ORDER BY子句是否会影响查询性能
  2. 为什么我的来信不如预期

无论哪种方式,要评估ORDER BY子句,都需要对表达式进行求值,以便确定顺序。在第一个示例中,您需要指定表达式,因为这些列不包含在SELECT语句中。

但是,在第二个查询中,您选择了要排序的列,并且由于对ORDER BY的评估是 AFTER ,因此整个查询已处理完毕,您只需使用列< ORDER BY子句中的em> ALIAS ,而不是再次执行该功能。

  

如果您要对ORDER BY子句中存在的表达式进行排序,则某些RDBMS查询优化器将转换SELECT语句中的表达式以为您使用列别名

您这样做是对的,但是由于响应中的重复项,因此您的字母计数表达式不是最新的。

您可以简单地更改COUNT表达式以使用一个独特的子句仅计算唯一值。

COUNT(DICTINCT t3.letter)

这使您的原始查询现在看起来像这样:

SELECT 
  t1.id, 
  t1.name

FROM 
  table1 t1

INNER JOIN 
  table2 t2
    ON t2.t1_id = t1.id

LEFT JOIN 
  table3 t3
    ON t3.t1_id = t1.id
      AND t3.letter IN ('a', 'b', 'c')

GROUP BY
  t1.id

ORDER BY
  COUNT(DICTINCT t3.letter) DESC,
  AVG(t2.number) DESC

答案 1 :(得分:0)

这将检索您的要求:

bash $ foo=
bash $ foo[34]=hello
bash $ foo[182]=world
bash $ echo ${foo[34]} ${foo[182]}
hello world