Sql查询left join

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Sql查询left join相关的知识,希望对你有一定的参考价值。

Sql查询left joinSelect distinct 子单信息.子单号,子单信息.尺码,Left(子单信息.颜色缸号,255) As 颜色,生产进度.加工类别 as 工序,Sum(Val(生产进度.排卡量)) As 排卡量,Sum(Val(生产进度.收货数)) As 收货数,Sum(Val(生产进度.收货重)) As 收货重 from [子单信息] Left join (Select 子单号,加工类别,排卡量,收货数,收货重 from [生产进度] Group by 子单号) 生产进度 On 子单信息.子单号=生产进度.子单号 Where 子单信息.子单号 like '18077%' Group by 子单信息.子单号,子单信息.尺码,Left(子单信息.颜色缸号,255),生产进度.加工类别 Order by 子单信息.子单号

运行时出错:from 子句错误。

题主的中间过渡虚拟查询表"生产进度"的分组查询语法有错误
... (Select 子单号,加工类别,排卡量,收货数,收货重 from [生产进度] Group by 子单号)
生产进度 on ...
请注意分组汇总查询时,除了汇总信息,未参与分组的字段不得出现在 select子句的输出字段列表中!
该查询中只有"子单号"一个字段参与分组,但是输出字段列表中却有"子单号"、"加工类别"、"排卡量"、"收货数"、"收货重" 这5个字段,显然违反了语法规则。
至于如何更正,因为不知道题主的意图和表结构,这里只可以给个参考写法,最终的正确写法请考题主自行解决。可参考下列写法进行修正
... (Select a.子单号,a.加工类别,sum(a.排卡量) as 排卡量,
sum(a.收货数) as 收货数 ,sum(a.收货重) as 收货重 from [生产进度] a
Group by a.子单号,a.加工类别) 生产进度 on ...
参考技术A 一看就是access数据库追问

有经验

SQL优化:慎用标量子查询,改用left join提升查询效率

一、项目实例问题

1、问题背景

  某个需求做了之后,注意到有个接口返回数据特别慢,特别是使用下面的 3 个字段排序时就直接卡死,肯定是 sql 性能写法问题,所以决定研究一下查看究竟。

  其实需求挺简单,有几个字段排序,前端需要展示那些字段,然后之前的后端写的 sql 如下,仅提取主要问题点,其实就是需要拿到 starCount、commentCount、totalReward 用来前端展示,而这三个字段呢,又需要从另外三个表里去分别计数,所以不考虑 sql 性能优化的话,就很容易想到了这种错误的写法。

k.tags,
v.views,
(select coalesce(count(rid),0) from table1 where aa = \'kl\' and rid = k.id) starCount,
(select coalesce(count(id),0) from table2 where aa = \'kl\' and rid = k.id::varchar) commentCount,
(select coalesce(count(id),0) from table3 where aa = \'kl\' and rid = k.id::varchar) totalReward
from table4 k left join table5 v on k.id = v.kl_id

2、优化方案

  主要优化后的 sql 如下:使用 left join 替代标量子查询

k.tags,
v.views,
coalesce (s.count,0) starCount,
coalesce (m.count,0) commentCount,
coalesce (p.count,0)  totalReward
from table4 k left join table5 v on k.id = v.kl_id 
left join (select rid,count(rid) from table1 where aa = \'kl\' group by rid) s on k.id = s.rid
left join (select rid,count(rid) from table2 where aa = \'kl\' group by rid) m on m.rid = k.id::varchar 
left join (select rid,count(rid) from table3 where aa = \'kl\' group by rid) p on p.rid = k.id::varchar 
order by totalReward desc

  优化前比如我有10万篇文章,那就要执行10万次(select coalesce(count(rid),0) from table1 where aa = \'kl\' and rid = k.id) starCount。

  优化后,仅需一次两表之间的匹配,即使是全表也是1次匹配,分组后也是1次匹配,数据量少是会提高效率但是顶多0.00几的提高,关键是left join。提高了n倍之前order by直接执行失败time out,优化之后是0.4s左右。

3、分析原因 - 为什么会想到错误的写法

  以前我确实很少看到第一种那种标量子查询的写法,所以很纳闷为什么会这样写。一般不都是用 left join 吗?后来了解到可能情况不一样:

(1)平常我们使用多表关联都会想到 left join,因为我们会用到关联表的多个字段或某个字段,需要将其查出来,所以很容易想到 left join。

(2)而这种情况只需要使用其他表的一个计数的值,没有使用表里的任何字段,没学过 sql 优化的,很难想到用 left join。

  而很多人使用标量子查询而不自知执行效率差,往往是因为数据量比较小,并没有发现不妥,一旦数据量大了之后,就会越来越慢。只有经过大数据量的考验,才能写出来优质的 sql。

  墨天轮平台有个标量子查询的优化案例可以看下:Oracle 标量子查询优化案例  —  https://www.modb.pro/db/41963

二、标量子查询的问题

  标量子查询、聚合标量子查询、行转列标量子查询、带top的标量子查询如何转成left join。

  之所以要转换,主要是因为标量子查询虽然写法上比较直观,容易理解,不用想就知道怎么写,但是存在:代码重复、多次访问同一个表 问题,所以效率比较低。

1、标量子查询的模板

  按标量子查询方式,写出来的sql,都类似下面的代码:

select tb.col1,
       tb.col2,
       --下面的代码是重复的,表和连接条件都类似,只是最后显示的字段不同
       (select x1 from t where t.id = tb.id) as x1,
       (select x2 from t where t.id = tb.id) as x2,
       (select x3 from t where t.id = tb.id) as x3,
       (select x4 from t where t.id = tb.id) as x4,
       ...
from tb

  可以看到,其中x1、x2、x3、x4等列,大部分代码都是重复的。当然,代码重复本身并没有太大的问题,最多就是复制粘贴,拷贝多次,然后把字段名改改,就行了。

2、标量子查询的执行过程

  上面的sql经过sql server的优化,生成执行计划,执行过程类似如下的过程:

(1)从tb表中取一条数据,用其中的id值,第1次和t表中的id值进行比较,如果相等,就返回t表的x1字段的值。

(2)从tb表中取一条数据,用其中的id值,第2次和t表中的id值进行比较,如果相等,就返回t表的x2字段的值。

(3)从tb表中取一条数据,用其中的id值,第3次和t表中的id值进行比较,如果相等,就返回t表的x3字段的值。

(4)从tb表中取一条数据,用其中的id值,第4次和t表中的id值进行比较,如果相等,就返回t表的x4字段的值。

(5)按照上述过程遍历整个tb表的每一条数据。

  从上面的过程可以看出,一共访问了t表4次,做了很多无用功。

  如果改成left join的方式,只需要访问1次t表,少访问3次,效率提高不少。

  所以,要尽量少用标量子查询的写法。

以上是关于Sql查询left join的主要内容,如果未能解决你的问题,请参考以下文章

Sql查询left join

我想提高 JOIN SQL 性能

ORACLE LEFT JOIN 子查询 在SQL SERVER中可以使用如图中的子查询,ORACLE中怎么实现

SQL LEFT JOIN 子查询别名

通过 LEFT JOIN 优化 SQL 子查询

关于SQL 查询效率问题 left join 改成 inner join union