我在PostgreSQL 11.3上有两个表:
销售:
+------------+-----------+--------+----------+-----------+ | event_week | store_num | fsaldu | latitude | longitude | +------------+-----------+--------+----------+-----------+ | 201946 | 11249 | K2K3C2 | null | null | | 201947 | 11250 | V6B0G5 | null | null | | 201948 | 11251 | N9H0G6 | null | null | +------------+-----------+--------+----------+-----------+
fsa_latlong :
+--------+-------+------+--------------------+-----------+ | fsaldu | fsa5 | fsa4 | latitude | longitude | +--------+-------+------+--------------------+-----------+ | K2K3C2 | K2K32 | K2K3 | 47.006479999999996 | -52.9587 | | V6B0G5 | V6B0G | V6B0 | 47.416990000000006 | -53.19438 | | N9H0G1 | N9H0G | N9H0 | 47.326370000000004 | -52.80969 | | N9H0G2 | N9H0G | N9H0 | 47.326370000000004 | -52.80969 | | N9H0G3 | N9H0G | N9H0 | 47.326370000000004 | -52.80969 | | N9H0G4 | N9H0G | N9H0 | 47.326370000000004 | -52.80969 | | N9H0G5 | N9H0G | N9H0 | 47.326370000000004 | -52.80969 | +--------+-------+------+--------------------+-----------+
我想执行联接以更新 fsa_latlong 表中 sales 表中的纬度和经度 。这是通过以下查询完成的:
update sales s
set latitude = l.latitude,
longitude = l.longitude
from fsa_latlong l
where s.fsaldu = l.fsaldu;
但是,由于邮递区号已退役,销售表中的某些 fsaldu 值在 fsa_latlong 表中不匹配或重新分配。
因此,我要完成的工作是从 fsa5 或 fsa4 纬度和经度 >不能与整个邮政编码完全匹配。
我的第一次尝试是在第一次连接完成后使用第二个查询。
update sales s
set latitude = (SELECT AVG(l.latitude)
FROM fsa_latlong l
WHERE s.latitude is null
AND (
l.fsa5 = substring(s.fsaldu, 1, 5)
OR l.fsa4 = substring(s.fsaldu, 1, 4)
)),
longitude = (SELECT AVG(l.longitude)
FROM fsa_latlong l
WHERE s.longitude is null
AND (
l.fsa5 = substring(s.fsaldu, 1, 5)
OR l.fsa4 = substring(s.fsaldu, 1, 4)
));
但是,这没有按要求进行。理想情况下,我想通过一个查询来完成此操作,我怀疑它使用CASE
语句或COALESCE
来计算初始匹配为null时的汇总。
任何帮助,我们将不胜感激。
答案 0 :(得分:1)
类似的东西应该可以工作(未经测试):
WITH
average_values AS (
SELECT s.fsaldu,
AVG(l.latitute) AS avg_latitude,
AVG(l.longitude) AS avg_longitude
FROM sales s
LEFT
JOIN fsa_latlong fl
ON l.fsa5 = substring(s.fsaldu, 1, 5)
OR l.fsa4 = substring(s.fsaldu, 1, 4)
GROUP BY 1
),
selected_values AS (
SELECT av.fsaldu,
coalesce(fl.laitude, av.avg_latitude) AS latitude,
coalesce(fl.longitude, av.avg_longitude) AS longitue
FROM average_values av
LEFT
JOIN fsa_latlong fl
ON wf.fsaldu = fl.fsaldu
)
UPDATE sales s
SET latitude = sv.latitude,
longitude = sv.longitude
FROM selected_values sv
WHERE s.fsaldu = sv.fsaldu;
注意:
另一项一般性说明-将CTE用于子查询,CTE具有可读性和高效性(例如,您不必在单独的位置计算经度/纬度)。
答案 1 :(得分:0)
我个人比较喜欢逐步进行这种事情。在这种情况下,通过测试前面的步骤是否失败(通过纬度/经度为NULL)来确定条件。
UPDATE sales s
SET latitude = l.latitude
,longitude = l.longitude
FROM fsa_latlong l
WHERE s.fsaldu = l.fsaldu;
UPDATE sales s
SET latitude = agg.latitude
,longitude = agg.longitude
FROM (SELECT l.fsa5
, AVG(l.latitude) AS latitude
, AVG(l.longitude) AS longitude
FROM fsa_latlong l
GROUP BY l.fsa5
) agg
WHERE agg.fsa5 = substring(s.fsaldu, 1, 5)
AND (s.latitude is null OR s.longitude is null)
;
UPDATE sales s
SET latitude = agg.latitude
,longitude = agg.longitude
FROM (SELECT l.fsa4
, AVG(l.latitude) AS latitude
, AVG(l.longitude) AS longitude
FROM fsa_latlong l
GROUP BY l.fsa4
) agg
WHERE agg.fsa4 = substring(s.fsaldu, 1, 4)
AND (s.latitude is null OR s.longitude is null)
;
答案 2 :(得分:0)
让我假设sales
每行都有一个唯一的ID,我将其称为sale_id
:
UPDATE sales
SET latitude = COALESCE(l.latitude, l5.latitude, l4.latitude),
longitude = COALESCE(l.longitude, l5.longitude, l4.longitude)
FROM sales s LEFT JOIN
fsa_latlong l
ON s.fsaldu = l.fsaldu LEFT JOIN
(SELECT SUBSTR(fsaldu, 1, 5) fsaldu5, AVG(latitude) as latitude, AVG(longitude) as longitude
FROM fsa_latlong l
GROUP BY SUBSTR(fsaldu, 1, 5)
) l5
ON l5.fsaldu5 = SUBSTR(s.fsaldu, 1, 5) LEFT JOIN
(SELECT SUBSTR(fsaldu, 1, 4) as fsaldu4, AVG(latitude) as latitude, AVG(longitude) as longitude
FROM fsa_latlong l
GROUP BY SUBSTR(fsaldu, 1, 4)
) l4
ON l4.fsaldu4 = SUBSTR(s.fsaldu, 1, 4)
WHERE s.sales_id = sales.sales_id;