2011-05-12 134 views
9

我有一个邮政编码表,我想用它的3个最近的邻居更新每个邮政编码。即填补空白此表:mySQL - 使用select返回多行更新多列

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中返回的行将被放入一个可用于更新多个字段的表单中? 谢谢。

+0

“最近的邮政编码”是如何确定的? – Thomas 2011-05-12 22:34:42

+0

@Thomas纬度和经度也存储在邮政编码表中,我转换为米和使用pythageros – spiderplant0 2011-05-12 22:45:56

回答

10
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' 
+0

谢谢@Thomas。这工作。然而,我需要扩展代码,我无法弄清楚“Min(Case When Z1.Num = 1 Then Z1.postcode End)As PostCode1”的含义。我认为“敏”是用于“群”。我试图用“IF(@ rownum = 1,postcode,''))AS PostCode1”替换它们,但我无法让它工作。你能解释一下“Min(Case ...)”是如何工作的 – spiderplant0 2011-05-13 13:18:45

+0

@ spiderplant0 - 通常情况下,Min与Group By一起使用,但是如果每个列都包含在一个聚合函数中(如“Z”派生表) – Thomas 2011-05-13 16:45:21

+0

@ spiderplant0 - 您应该使用'Case'而不是'If'作为'Case'符合ANSI标准。注意,我必须在它自己的派生表(Z1)中计算顺序,然后评估我的表达式像Z1.Num = 1. – Thomas 2011-05-13 16:46:59

0

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

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

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

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

+0

谢谢@ james-c我应该说明我的选择查询返回3行而不是3列。即它会返回最接近的3个邮编。我已经添加了一些更多的原始问题来解释这一点。 – spiderplant0 2011-05-12 22:48:34

+0

用于选择查询以找到3个最接近的邮政编码实际的SQL是\t SELECT邮编FROM postcode_table \t其中 \t LAT>。 “($ LAT - $ deltaLat)” 和 \t LAT <“($ LAT + $ deltaLat) “和 \t LNG>”($ LNG - 。。。$ deltaLng) “和 \t LNG <”($ LNG + $ deltaLng)“和 \t活性= '1' \t ORDER BY \t POW(lat - $ lat,2)+ \t POW((lng - $ lng)* $ lat2LngAdjust,2) \t ASC \t限制3 – spiderplant0 2011-05-12 22:50:54

+0

我怀疑你可以用存储过程做到这一点,但我恐怕没有这方面的知识。我可能会用一些简单的包装逻辑(例如PHP)来处理这个问题,该逻辑运行第一个查询,提取值并创建更新语句。理论上,您可以对多个邮政编码运行“SELECT”查询,对结果进行批量处理,然后创建一个大的多行REPLACE语句。 – 2011-05-12 22:52:17

1

你可以做一些类似这样的东西:

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

我发现此相关的问题#2如何列转换为行:

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()功能的黑客:

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

谢谢@peter然而,是pc1,pc2和pc3列?我的选择查询返回3行而不是3列。即它会返回最接近的3个邮编。我已经添加了一些更多的原始问题来解释这一点。 – spiderplant0 2011-05-12 22:43:39

+0

我的意思是谢谢Ravi-Gummadi :) – spiderplant0 2011-05-12 22:57:40

+0

@ spiderplant0:修改了答案。我没有有效地运行查询,所以只是将它视为伪代码。 – rkg 2011-05-12 23:08:15

-1

每当我看到一个表,有他们的名字后1专柜专栏中,我得到关注。

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

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

+0

@ chris-morgan计算3个最接近的邮政编码需要很长时间才能运行。但是,这只需要一次完成,后续的需要这些信息的数据库查询需要快速。关于是否坏主意的决定实际上总是取决于背景。 – spiderplant0 2011-05-12 22:56:17

+0

@ spiderplant0我明确地认识到,背景很重要,我总是喜欢在灵活性方面犯错,因为变化通常是有保证的。 – 2011-05-12 23:10:20