Search code examples
sqlsql-updatesubqueryderby

How can I "Update Select" some values in a column with a subquery?


I am using Apache Derby DB (SQL) version 10.14 and this is the Derby Reference Manual: https://db.apache.org/derby/docs/10.14/ref/refderby.pdf

I am trying to create a star schema and am currently working on the region dimension table.

These are the tables I am using: DWH_PRICE_PAID_RECORDS enter image description here

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 enter image description here

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));

And DIM_REGION enter image description here

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));

First I inserted Town(unique), County and District:

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

enter image description here

Town has to be unique because I dont have anything else as identifier to match/link the tables. The DIM_REGION table now has 938 unique town records and I want to "UPDATE" the remaining columns "Latitude", "Longitude" and "COUNTRY_STRING". The DWH_POSTCODES table has 1637 unique town records which means the towns are different! Only 532 towns are matching and only those shall be updated in the DIM_REGION table.

I'm starting with just one column "Latitude" and this is what I would expect it to look like after the Update statement: enter image description here

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);

but when I do that I get this error message (the error message is german and I had to translate, sorry):

ERROR 21000 a scalar subquery returned more than one value

I don't understand why. If I commit just the select statement:

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

I get exactly what I expected to get and thats the whole column with all latitudes.

Thank you very much!


Solution

  • IBM Db2 and Apache Derby DB are completely different products. So, remove the db2 tag.
    You provided absolutely non-matched lists of towns in both tables. Was it so hard to prepare matched data sets?

    If you don't have duplicates in the dwh_postcodes.town column, then update should look like this (may be with the same subselect in the EXISTS predicate in WHERE):

    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
    )
    */
    ;
    

    Otherwise you have to use some aggregate function (or the fetch first clause if Derby supports it) to make this subselect return only 1 row as shown commented out in the example above.

    Alternatively, you could do 1 INSERT instead of INSERT and UPDATE to fill all 4 columns:

    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;