如何在带有子查询的列中“更新选择”某些值?

Posted

技术标签:

【中文标题】如何在带有子查询的列中“更新选择”某些值?【英文标题】:How can I "Update Select" some values in a column with a subquery? 【发布时间】:2019-06-03 23:26:25 【问题描述】:

我使用的是 Apache Derby DB (SQL) 版本 10.14,这是 Derby 参考手册:https://db.apache.org/derby/docs/10.14/ref/refderby.pdf

我正在尝试创建星型模式,目前正在处理区域维度表。

这些是我正在使用的表格: DWH_PRICE_PAID_RECORDS

TRANSACTION_ID                          PRICE   DATE_OF_TRANSFER    PROPERTY_TYPE   OLD_NEW     DURATION    TOWN_CITY               DISTRICT                COUNTY                  PPDCATEGORY_TYPE    RECORD_TYPE
FDD12C8B-5A02-4B3F-8C67-9BC523DC780B  71000   15.09.2000 00:00    D                   N       F           SCUNTHORPE              NORTH LINCOLNSHIRE      NORTH LINCOLNSHIRE      A                       A
70F7F480-4A9A-4FEB-A58A-2B964605BFD2  97000   01.08.2002 00:00    F                   N       L           MANCHESTER              SALFORD                 GREATER MANCHESTER      A                       A
64D48FA9-8C85-49D6-AF5A-23FABDDB4FEB  104000  17.01.2006 00:00    S                   N       L           ROCHDALE                ROCHDALE                GREATER MANCHESTER      A                       A
F0316F65-E375-4DC4-BCDF-3FDC054ADE9C  188500  18.05.2015 00:00    S                   N       F           KIDDERMINSTER           MALVERN HILLS           WORCESTERSHIRE          A                       A
2EC5A85B-7BEF-4127-B3D0-6B416899CAEB  180000  07.05.1999 00:00    S                   N       F           KINGSTON UPON THAMES    KINGSTON UPON THAMES    GREATER LONDON          A                       A
21E5FEB7-A62E-2439-E050-A8C06205342E  55000   28.08.2015 00:00    T                   N       F           MOUNTAIN ASH            RHONDDA CYNON TAFF      RHONDDA CYNON TAFF      B                       A
3E0330F0-0F44-8D89-E050-A8C062052140  77000   30.08.2016 00:00    T                   N       F           WALLASEY                WIRRAL                  MERSEYSIDE              A                       A
D43A8B4A-6272-4706-9189-30F8E24EDF13  210000  23.05.2007 00:00    S                   N       F           BRISTOL                 NORTH SOMERSET          NORTH SOMERSET          A                       A
3575DAF5-0E80-408F-9970-FDF5D1475E73  185000  16.11.2007 00:00    S                   N       F           CREWKERNE               SOUTH SOMERSET          SOMERSET                A                       A
A4246390-61F4-4228-BC82-79D3F369CA34  32700   12.12.1996 00:00    F                   N       L           SOUTHAMPTON             SOUTHAMPTON             SOUTHAMPTON             A                       A

CREATE TABLE "DWH_PRICE_PAID_RECORDS" ("TRANSACTION_ID" VARCHAR(50) NOT NULL, "PRICE" INTEGER, "DATE_OF_TRANSFER" DATE NOT NULL, "PROPERTY_TYPE" CHAR(1), "OLD_NEW" CHAR(1), "DURATION" CHAR(1), "TOWN_CITY" VARCHAR(50), "DISTRICT" VARCHAR(50), "COUNTY" VARCHAR(50), "PPDCATEGORY_TYPE" CHAR(1), "RECORD_TYPE" CHAR(1));

DWH_POSTCODES

Postcode    Eastings    Northings   Latitude    Longitude           Town            Region          UK_Region   Country_Code    Country_String
AB10        392900      804900      5,713,514   -211,731        Aberdeen            Aberdeen City   Scotland    SCT             Scotland
AB13        385600      801900      5,710,801   -223,776        Milltimber          Aberdeen City   Scotland    SCT             Scotland
AB14        383600      801100      5,710,076   -227,073        Peterculter         Aberdeen City   Scotland    SCT             Scotland
AB21        387900      813200      572,096     -220,033        Aberdeen Airport    Aberdeen City   Scotland    SCT             Scotland
AB22        392800      810700      5,718,724   -211,913        Bridge of Don       Aberdeen City   Scotland    SCT             Scotland
AB30        370900      772900      5,684,678   -247,712        Laurencekirk        Aberdeenshire   Scotland    SCT             Scotland
AB31        368100      798300      5,707,479   -252,623        Banchory            Aberdeenshire   Scotland    SCT             Scotland
AB32        380800      807200      5,715,545   -231,742        Westhill            Aberdeenshire   Scotland    SCT             Scotland
AB33        355200      815100      5,722,464   -274,203        Alford              Aberdeenshire   Scotland    SCT             Scotland
AB34        350800      800600      5,709,393   -281,204        Aboyne              Aberdeenshire   Scotland    SCT             Scotland


CREATE TABLE "DWH_POSTCODES" ("POSTCODE_ID" INTEGER generated always as identity (start with 1 increment by 1), "POSTCODE" VARCHAR(10), "EASTINGS" VARCHAR(50), "NORTHINGS" VARCHAR(50), "LATITUDE" VARCHAR(10), "LONGITUDE" VARCHAR(10), "TOWN" VARCHAR(50) NOT NULL, "REGION" VARCHAR(50), "UK_REGION" VARCHAR(50), "COUNTRY_CODE" VARCHAR(20), "COUNTRY_STRING" VARCHAR(20));

还有 DIM_REGION

CREATE TABLE "DIM_REGION" ("REGION_ID" INTEGER generated always as identity (start with 1 increment by 1), "TOWN" VARCHAR(30), "COUNTY" VARCHAR(30), "DISTRICT" VARCHAR(30), "LATITUDE" VARCHAR(10), "LONGITUDE" VARCHAR(10), "COUNTRY_STRING" VARCHAR(20));

首先我插入城镇(唯一)、县和区:

INSERT INTO DIM_REGION (TOWN, County, District) SELECT town_city, MAX(county), MAX(district) FROM DWH_PRICE_PAID_RECORDS GROUP BY town_city;

Town 必须是唯一的,因为我没有其他任何东西作为标识符来匹配/链接表格。 DIM_REGION 表现在有 938 个唯一的城镇记录,我想“更新”剩余的列“纬度”、“经度”和“国家字符串”。 DWH_POSTCODES 表有 1637 条独特的城镇记录,这意味着城镇是不同的!只有 532 个城镇是匹配的,并且只有那些应该在 DIM_REGION 表中更新。

我只从一列“纬度”开始,这是我希望它在 Update 语句之后的样子:

UPDATE DIM_REGION SET DIM_REGION.LATITUDE = (SELECT DWH_POSTCODES.LATITUDE from dim_region join dwh_postcodes on dim_region.town = dwh_postcodes.town where dim_region.town = dwh_postcodes.town);

但是当我这样做时,我收到了这条错误消息(错误消息是德语,我不得不翻译,抱歉):

ERROR 21000 a scalar subquery returned more than one value

我不明白为什么。如果我只提交 select 语句:

SELECT DWH_POSTCODES.LATITUDE from dim_region join dwh_postcodes on dim_region.town = dwh_postcodes.town where dim_region.town = dwh_postcodes.town

我得到的正是我期望得到的,这就是所有纬度的整个专栏。

非常感谢!

【问题讨论】:

运行select语句时,返回多少行?更新纬度时,只能设置为 1 个值。 请在所有参与表格中提供一些示例数据以及所需的结果。还应指定 Db2 平台和版本。 @alexherm 你好,亚历克斯,谢谢!返回 532 行.. 但是我应该如何更新一整列。我不能手动更新每一行.. @MarkBarinstein 你好马克,谢谢!我会做出一些改变。 @Flippi 请使用文字而不是图片。我打算将这些数据与sql语句一起使用,并且从图片中重新键入数据需要更多时间... 【参考方案1】:

IBM Db2Apache Derby DB 是完全不同的产品。因此,请删除 db2 标签。 您在两个表中都提供了完全不匹配的城镇列表。准备匹配的数据集有那么难吗?

如果您在 dwh_postcodes.town 列中没有重复项,则 update 应如下所示(可能与 WHERE 中的 EXISTS 谓词中的 subselect 相同):

UPDATE DIM_REGION SET DIM_REGION.LATITUDE = 
(
SELECT 
--MAX (
DWH_POSTCODES.LATITUDE 
--)
from dwh_postcodes 
where dim_region.town = dwh_postcodes.town
-- fetch first 1 row only
)
/*
WHERE EXISTS 
(
SELECT 1
from dwh_postcodes 
where dim_region.town = dwh_postcodes.town
)
*/
;

否则,您必须使用一些聚合函数(或 fetch first 子句,如果 Derby 支持它)来使此 subselect 仅返回 1 行,如上面示例中注释掉的那样。

或者,您可以执行 1 INSERT 而不是 INSERT 和 UPDATE 来填充所有 4 列:

INSERT INTO DIM_REGION (TOWN, County, District, latitude) 
SELECT p.town_city, p.county, p.district, d.latitude
FROM (
SELECT town_city, MAX(county) county, MAX(district) district
FROM DWH_PRICE_PAID_RECORDS 
GROUP BY town_city
) p
join dwh_postcodes d on p.town_city = d.town;

【讨论】:

你是我的英雄!非常感谢你。使用您的替代“插入”语句,我只能得到 532 条记录。我想要的是获取所有 938 个唯一的城镇记录,并且只有那些匹配的城镇的纬度、经度、国家字符串,否则纬度、经度、国家字符串应该保持为 NULL。但是我通过您的第一个“更新”声明实现了这一点!所以谢谢你一百次!我在这里真的很努力.. :) 在最新的INSERT 中使用left join 而不是join【参考方案2】:

当您需要更新多行时使用下面的查询。

UPDATE A SET A.LATITUDE = B.LATITUDE 
FROM DIM_REGION as A JOIN DWH_POSTCODES B  
ON A.TOWN = B.TOWN 
WHERE A.TOWN = B.TOWN

【讨论】:

嗨,杰夫斯,谢谢!不幸的是,我认为 Derby DB 在 UPDATE 语句中不支持 FROM。至少我在 Derby 参考手册db.apache.org/derby/docs/10.4/ref/index.html 中找不到它。它说 ERROR 42x01 Syntaxerror: Encountered "FROM" at line 3, column1。【参考方案3】:

您遇到的错误是因为您的子查询返回了超过 1 条记录。您需要将子查询的结果限制为 1。否则,它将不起作用。

或者,您可以将子查询与 TOP 1

一起使用
UPDATE DIM_REGION SET DIM_REGION.LATITUDE = (SELECT TOP 1 DWH_POSTCODES.LATITUDE from dim_region join dwh_postcodes on dim_region.town = dwh_postcodes.town where dim_region.town = dwh_postcodes.town);

希望这会有所帮助。

【讨论】:

嗨,Shahzada,谢谢!不幸的是,derby DB 不支持 TOP。功能似乎(我在参考手册db.apache.org/derby/docs/10.4/ref/index.html 中找不到)。我总是收到错误:ERROR 42X01 Syntaxerror Encountered "1" at line 3, column 13.【参考方案4】:

@flippi

在一个块中执行多个 UPDATE 语句的一种方法:

     BEGIN
       UPDATE ...
       UPDATE ...
       UPDATE ...
       ...
     END;

【讨论】:

以上是关于如何在带有子查询的列中“更新选择”某些值?的主要内容,如果未能解决你的问题,请参考以下文章

查询以从与给定值相同的列中选择值,但不同的行

如何在子查询的 WHERE 子句中使用来自 UNNEST 的多个值?

TSQL - 如何在另一列中提取具有最小值和最大值的列

SQL查询从postgresql数据库表中具有数组数据类型的列中获取数据。

我如何从Laravel中具有多行的列中扣除单个值

如何在子查询中使用主查询中的列?