【问题标题】:mySQL - update multiple columns with a select returning multiple rowsmySQL - 使用返回多行的选择更新多列
【发布时间】:2011-05-12 22:31:28
【问题描述】:

我有一个邮政编码表,我想用它最近的 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

无论如何,从选择返回的行是否可以放入可用于更新多个字段的表单中? 谢谢。

【问题讨论】:

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

标签: mysql


【解决方案1】:
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'

【讨论】:

  • 谢谢@Thomas。这行得通。但是我需要扩展代码,我无法弄清楚“Min(Z1.Num = 1 时的情况,然后 Z1.postcode End)作为 PostCode1”的含义。我认为“Min”与“group by”一起使用。我试图用 "IF(@rownum=1,postcode,'') ) AS PostCode1" 等替换它们,但我无法让它工作。你能解释一下“Min(Case ...”的工作原理吗?
  • @spiderplant0 - 通常,Min 与 Group By 一起使用,但是,如果每一列都包含在聚合函数中(如“Z”派生表),则只返回一行。
  • @spiderplant0 - 您应该使用Case 而不是If,因为Case 符合ANSI。请注意,我必须在它自己的派生表 (Z1) 中计算顺序,然后评估我的表达式,如 Z1.Num = 1。
【解决方案2】:

你可以做类似这样的事情:

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

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

MySQL - Rows to Columns

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

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 [1] 中模拟 ROW_NUMBER() 功能的 hack:

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

【讨论】:

  • 谢谢@peter 但是是 pc1、pc2 和 pc3 列吗?我的选择查询返回 3 行而不是 3 列。 IE。它返回 3 个最接近的邮政编码。我在原来的问题中添加了更多内容以进一步解释这一点。
  • @spiderplant0:修改了答案。我还没有实际运行查询,所以只需将其视为伪代码。
  • @Ravi-Gummadi 感谢您的链接。
  • 我收到错误提示“FROM”不能放在那个位置
【解决方案3】:

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

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

查看真正的 SQL 会更容易指定它。

请注意,第一列在引号中指定为常量。为此,postcode 必须是 UNIQUEPRIMARY 索引。

【讨论】:

  • 谢谢@james-c 我应该解释一下我的选择查询返回 3 行而不是 3 列。 IE。它返回 3 个最接近的邮政编码。我在原来的问题中添加了更多内容以进一步解释这一点。
  • 用于查找最接近 3 个邮政编码的选择查询的实际 sql 是 SELECT postcode FROM postcode_table where lat > " . ($lat - $deltaLat) . " and lat " . ($lng - $deltaLng) . " and lng
  • 我怀疑你可以用存储过程来做到这一点,但恐怕我不知道怎么做。我可能会在运行第一个查询、提取值然后创建更新语句的(例如 PHP)中使用一些简单的包装逻辑来处理这个问题。理论上,您可以对多个邮政编码运行 SELECT 查询,将结果批处理,然后创建一个大的多行 REPLACE 语句。
  • 对于最接近的邮政编码,您不能只使用 pythag 来计算最接近的邮政编码吗?
  • @James-C 谢谢。 'where' 语句中的代码快速缩小搜索范围,'order by' 对其进行微调。我在“order by”中仅使用 Pythagerous 进行了尝试,但速度非常慢(180 万个邮政编码)。
【解决方案4】:

每当我看到一个表,其名称后有一个加一计数器的列,我都会担心。

一般来说,存储可以从已存储的数据中计算出来的数据是一个坏主意 (TM)。如果您的应用程序突然需要 4 个最接近的邮政编码会怎样?如果邮政编码边界发生变化怎么办?

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

【讨论】:

  • @chris-morgan 计算最近的 3 个邮政编码需要很长时间才能运行。但这没关系,因为它只需要执行一次,并且需要此信息的后续数据库查询需要它快速。关于某事是否是一个坏主意的决定几乎总是取决于上下文。
  • @spiderplant0 我非常理解上下文很重要,我总是喜欢在灵活性方面犯错,因为通常可以保证更改。
猜你喜欢
  • 2013-09-30
  • 1970-01-01
  • 2015-11-11
  • 2018-12-08
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 2021-05-06
  • 1970-01-01
相关资源
最近更新 更多