首页 > 数据库 >MySQL将子查询中的结果引用更新目标表

MySQL将子查询中的结果引用更新目标表

时间:2023-01-03 14:44:08浏览次数:35  
标签:将子 ranking district tt 查询 MySQL DistrictProducts D0 D1

错误的SQL语句

为了排序,自然而然地想到了关联子查询。把原表跟自身关联,然后数出来每个地区集合中有多少个价格高于当前记录价格。如果有0个高于当前记录价格,就说明当前记录是该地区集合中价格最高的,ranking里就应该填入1;如果有1个高于当前记录价格,就说明当前记录的价格在该地区集合中排名第2……以此类推。可以看到,使用COUNT数出来高于当前记录价格的价格数后,还要再加上1,才能得到当前记录的ranking。
按照上面的思路很容易编写出以下SQL语句:

UPDATE DistrictProducts AS D1
SET D1.ranking = (SELECT COUNT(D2.price)+1
                  FROM DistrictProducts AS D2
                  WHERE D1.district=D2.district AND D1.price<D2.price);

从逻辑上讲没有问题,在其他的一些数据库中也确实可以完成对数据表的更新,但是在MySQL中执行会报错,报错信息如下:

这是因为MySQL不支持在子查询中引用更新目标表。
我们要更新的就是DistrictProducts这张表,而在子查询的FROM语句中还从这张表查询出数据,这在MySQL中是不被允许的。之所以有这个规定,也是考虑到了数据安全。

解决方法

1. 多嵌套版本

既然不允许在FROM子句里引用更新目标表,那我们就对从目标表里查询出来的数据再查询一次,相当于生成一个临时表。从外层来看,FROM子句里引用的是另外一张表(临时表),这就不会违背刚才提到的原则。
最终写出来的SQL语句如下:

UPDATE DistrictProducts AS D0
SET D0.ranking = (SELECT rank1
                  FROM (SELECT D1.district,D1.name,(SELECT COUNT(D2.price)+1
                                                    FROM DistrictProducts AS D2
                                                    WHERE D1.district=D2.district AND D1.price<D2.price) AS rank1
                                                    FROM DistrictProducts AS D1) AS tt
                  WHERE D0.district=tt.district AND D0.name=tt.name);

上面的语句存在不少嵌套,可以先看里面(SELECT D1.district……) AS tt这部分。这个tt就是我们给临时表取的名字,它有三列,分别是district,name和rank1.其中,rank1就对应着目标表的ranking列。知道了tt的结构,我们就可以在头脑里把这一大串SQL语句简化为:

UPDATE DistrictProducts AS D0
SET D0.ranking = (SELECT rank1
                  FROM tt
                  WHERE D0.district=tt.district AND D0.name=tt.name);

tt里就包含着我们要填写到ranking列的数据,我们只要对目标表和tt也来一个关联子查询,关联条件是district和name都相同,这样就能找到相应的正确ranking值填入数据表。

2. 多表更新减少嵌套版本

如果觉得上面的SQL语句嵌套实在太多了,还可以把生词临时表tt的语句挪到UPDATE子句中:

UPDATE DistrictProducts AS D0,(SELECT D1.district,D1.name,(SELECT COUNT(D2.price)+1
                                                           FROM DistrictProducts AS D2
                                                           WHERE D1.district=D2.district AND D1.price<D2.price) AS rank1
                               FROM DistrictProducts AS D1) AS tt
SET D0.ranking = tt.rank1
WHERE D0.district=tt.district AND D0.name=tt.name;

这回SQL语句的整体结构变成了多表更新。我们会目标表写入数据,另外一个临时表tt是用来提供数据的。

我们还是可以在头脑里把这些语句简化一下:

UPDATE DistrictProducts AS D0,tt
SET D0.ranking = tt.rank1
WHERE D0.district=tt.district AND D0.name=tt.name;

这样一看,结构一目了然。

针对我的业务需求,因为需要内部表关联到需要修改表的字段,所以采用的2. 多表更新减少嵌套版本显得更灵活一些

标签:将子,ranking,district,tt,查询,MySQL,DistrictProducts,D0,D1
From: https://www.cnblogs.com/mihutao/p/17022169.html

相关文章

  • Mysql的安装
    Mysql的安装1windows两种安装方式,入门选手推荐第二种(win10演示)Mysql官网下载地址:https://dev.mysql.com/downloads/mysql/2开始准备安装进入官网,这里我选择的......
  • 数据库SQL查询
    --查询表空间SELECTa.tablespace_name,a.bytes/1073741824total,b.bytes/1073741824used,c.bytes/1073741824free,(b.bytes*100)/a.bytes"%USED",(c.byte......
  • 软件开发入门教程网 Search之MySQL 元数据
        ......
  • 查询锁表
    --查询锁表语句SELECT  A.USERNAME,  A.MACHINE,  A.PROGRAM,  A.SID,  A.SERIAL#,  A.STATUS,  C.PIECE,  C.SQL_TEXTFROM  V$SESSIONA,......
  • MySQL压缩版安装与卸载
    MySQL压缩版安装与卸载安装​ 1、压缩包下载地址:https://dev.mysql.com/downloads/mysql/​ 选择Windows(x86,64-bit),ZIPArchive版本即可​ 2、下载后解压​ 3、......
  • MYSQL优化
    PerformanceSchema程序插桩消费者表是一个经常受到批评的特性。早期版本的MySQL对其的实现不够理想,导致资源消耗较高。通常的建议是干脆关掉它。这也被认为是难以理解......
  • Windows Server 2012 R2上PHP、MySQL环境搭建
    一、准备工具服务器操作系统:WindowsServer2012PHP版本:5.6.9(根据自己需要)MySQL版本:MySQL8.0.17二、相关软件下载1、PHP下载​​​https://windows.php.net/downloads/relea......
  • 分页查询功能
    分页查询功能分析好处:减轻服务器内存的开销提升用户体验      分析具体步骤PageBean实体类:packagecom.example.domain;importjava.util.L......
  • 第十七章《MySQL数据库及SQL语言简介》第2节:MySQL数据库的下载、安装和配置
    ​MySQL数据库被广泛应用于各种行业软件,它开发了针对各种不同操作系统都开发了的版本。本节以Windows版本为例介绍MySQL数据库的下载、安装和配置。17.2.1MySQL的下载读者可......
  • Mysql为什么用B+树做索引而不用B-树或红黑树?
    一、概述B+树只有叶节点存放数据,其余节点用来索引,而B-树是每个索引节点都会有Data域。所以从Mysql(Inoodb)的角度来看,B+树是用来充当索引的,一般来说索引非常大,尤其是关系性数......