问题 mySQL - 使用select返回多行来更新多个列


我有一个邮政编码表,我想用3个最近的邻居更新每个邮政编码。即填写此表中的空白:

postcode  nearestPostcode1  nearestPostcode2  nearestPostcode3
_______________________________________________________________

KY6 1DA      -                -                  -
KY6 1DG      -                -                  -
KY6 2DT      -                -                  -
KY6 1RG      -                -                  -
....

我已经找到了一个SELECT查询来查找最近的邮政编码,这是第一行可以更新的一种笨拙的方式:

update table1 set 
nearestPostcode1 = (select query for returning the first nearest postcode),
nearestPostcode2 = (select query for returning the second nearest postcode),
nearestPostcode3 = (select query for returning the third nearest postcode)
where postcode = 'KY6 1DA';

但是,这将导致为每个行更新运行3个选择查询。如果有一些方法来执行这个伪代码所表达的内容,那将会更有效:

update table1 set 
(nearestPostcode1, nearestPostcode2, nearestPostcode3) = 
(select query to return the 3 nearest postcodes)
where postcode = 'KY6 1DA';

上面的“选择查询”如下所示:

select postcode from postcodeTable 
order by <equation to calculate distance> ASC 
limit 3

无论如何,从select返回的行被放入一个可以用来更新多个字段的表单中吗? 谢谢。


2074
2018-05-12 22:31


起源

如何确定“最近的邮政编码”? - Thomas
@Thomas纬度和经度也存储在邮政编码表中,我转换为米并使用pythageros - spiderplant0


答案:


Update Table1
    Cross Join  (
                Select Min( Case When Z1.Num = 1 Then Z1.postcode End ) As PostCode1
                    , Min( Case When Z1.Num = 2 Then Z1.postcode End ) As PostCode2
                    , Min( Case When Z1.Num = 3 Then Z1.postcode End ) As PostCode3
                From    (
                        Select postcode 
                            , @num := @num + 1 As Num
                        From postcodeTable 
                        Where postcode = 'KY6 IDA'
                        Order By <equation to calculate distance> ASC 
                        Limit 3
                        ) As Z1
                ) As Z
Set nearestPostCode1 = Z.PostCode1
    , nearestPostCode2 = Z.PostCode2
    , nearestPostCode3 = Z.PostCode3
Where Table1.postcode =  'KY6 IDA'

11
2018-05-12 22:56



谢谢@Thomas。这很有效。但是我需要扩展代码,我不能弄清楚“Min(Z1.Num = 1然后Z1.postcode结束时的情况)作为PostCode1”的含义。我认为“Min”用于“group by”。我试图用“IF(@ rownum = 1,邮政编码,''))AS PostCode1”等替换它们,但我不能让它工作。你能解释一下“闽(案例......)如何运作”。 - spiderplant0
@ spiderplant0 - 通常,Min与Group By一起使用,但是,如果每个列都包含在聚合函数中(如“Z”派生表),则只返回一行。 - Thomas
@ spiderplant0 - 你应该用 Case 代替 If 如 Case 符合ANSI标准。请注意,我必须在自己的派生表(Z1)中计算顺序,然后评估我的表达式,如Z1.Num = 1。 - Thomas
谢谢@Thomas .. - spiderplant0


你可以做类似的事情:

UPDATE table1
SET
nearestPostcode1 = pc1,
nearestPostcode2 = pc2,
nearestPostcode3 = pc3
FROM 
(SELECT pc1, pc2, pc3 FROM ....) t
WHERE 
postcode = 'KY6 1DA';

我在Stackoverflow上找到了关于如何将列转换为行的相关问题:

MySQL - 行到列

在你的情况下,你可以做类似的事情

SELECT 
IF(@rownum=1,postcode,'') ) AS pc1, 
IF(@rownum=2,postcode,'') ) AS pc2, 
IF(@rownum=3,postcode,'') ) AS pc2, 
FROM
(SELECT postcode 
FROM postcodeTable 
ORDER BY <equation to calculate distance> ASC 
LIMIT 3)

这是一个模拟MySQL中的ROW_NUMBER()功能的hack [1]:

SELECT @rownum:=@rownum+1 rownum, t.*
FROM (SELECT @rownum:=0) r, mytable t;

1
2018-05-12 22:37



谢谢@peter然而是pc1,pc2和pc3列?我的选择查询返回3行而不是3列。即它返回3个最接近的邮政编码。我在原始问题中添加了一些内容来解释这一点。 - spiderplant0
我的意思是感谢Ravi-Gummadi :) - spiderplant0
@ spiderplant0:修改了答案。我没有动手运行查询,所以只需将其视为伪代码。 - rkg
@ Ravi-Gummadi感谢您的链接。 - spiderplant0
我收到错误,说“FROM”不能放在那个位置 - Dinesh


我想你可以用伪代码做到这一点:

REPLACE INTO table1 (postcode, nearestPostcode1, nearestPostcode2, nearestPostcode3)
    SELECT "KY6 1DA", col1, col2, col3 FROM myTable WHERE ...;

看到它真正的SQL就更容易了。

请注意,第一列被指定为引号中的常量。为此工作 postcode 必须是一个 UNIQUE 要么 PRIMARY 指数。


0
2018-05-12 22:36



谢谢@james-c我应该解释我的select查询返回3行而不是3列。即它返回3个最接近的邮政编码。我在原始问题中添加了一些内容来解释这一点。 - spiderplant0
用于查找3个最接近的邮政编码的select查询的实际sql是SELECT postcode FROM postcode_table其中lat>“。($ lat - $ deltaLat)。”和lat <“。($ lat + $ deltaLat)。”和lng>“ 。($ lng - $ deltaLng)。“和lng <”。($ lng + $ deltaLng)。“和active ='1'ORDER BY POW(lat - $ lat,2)+ POW((lng - $ lng) * $ lat2LngAdjust,2)ASC限制3 - spiderplant0
我怀疑你可以用存储过程做到这一点,但我担心我不知道如何。我可能会使用一些简单的包装逻辑来处理这个问题(例如PHP),它运行第一个查询,提取值然后创建更新语句。理论上你可以运行 SELECT 查询多个邮政编码,批量处理结果,然后创建一个大的多行 REPLACE 声明。 - James C
对于最近的邮政编码你不能只用pythag来计算出最接近的邮编吗? - James C
@ James-C谢谢。 'where'语句中的代码可以快速缩小搜索范围,并且'order by'可以对其进行微调。我在'order by'中只用了Pythagerous来尝试它,它非常慢(180万个邮政编码)。 - spiderplant0


任何时候我看到一个表格,其列名在他们的名字后面有一个计数器,我很担心。

通常,存储可以从已经存储的数据计算的数据是坏想法(TM)。如果您的应用程序突然需要,会发生什么 4 最近的邮政编码?如果邮政编码边界发生变化怎么办?

假设距离计算不是很复杂,从长远来看,你最好不要明确地存储这些数据。


-1
2018-05-12 22:49



@ chris-morgan计算3个最接近的邮政编码需要很长时间才能运行。但这没关系,因为它只需要完成一次,而后续需要此信息的数据库查询需要快速完成。关于某事物是否是一个坏主意的决定实际上总是取决于具体情况。 - spiderplant0
@ spiderplant0我非常感谢上下文的重要性,我总是喜欢在灵活性方面犯错误,因为改变通常是有保障的。 - Chris Morgan