tags:

views:

27

answers:

2

Hello,

I have a MySQL table with about 1000 rows, filled with different types of fruit trees and their locations on a farm. The data looks like this:

Fruit Trees Location on Farm

  7 |
  6 |    G G
  5 |    G   
Y 4 |    G   G
  3 |      A X G G
  2 |    A A A
  1 |_ _ _ _ _ _ _ 
     1 2 3 4 5 6 7
           X

Fruit Trees MySQL Table

 ID   Type    X  Y
 --   ----    -- --
 1    Apple   3  2
 2    Grape   3  4
 3    Grape   3  5
 4    Grape   3  6
 5    Apple   4  2
 6    Apple   4  3
 7    Grape   4  6
 8    Apple   5  2
 9    Grape   5  4
10    Grape   6  3
11    Grape   7  3

Now, I am looking to query this table to get the nearest "3" trees only of each type from the center X (5,3).

The query result should return something like:

 ID   Type    X  Y
 --   ----    -- --
 6    Apple   4  3
 5    Apple   4  2
 8    Apple   5  2
 9    Grape   5  4
10    Grape   6  3
11    Grape   7  3

There may be several trees with the same distance from the center but that should not matter because once the maximum number of nearest trees (3) is meet then we wouldn't include anymore trees from that type of tree. Hope this makes sense.

To get the distance from the center X to a nearby tree I use the below formula:

Distance = SQRT( POW(ABS(5 - X),2) + POW(ABS(3 - Y),2) )

Here is a reference that I have been trying to use: http://stackoverflow.com/questions/839704/sum-until-certain-point-mysql

How would I write a MySQL query to get the results? I may have to write several queries to do this but am just unsure how to structure it all.

Thank you

+1  A: 

Maybe this?

select id, type, x, y
from fruit_trees as ft1
where not exists (
    select null
    from fruit_trees as ft2
    where 
    ft2.type = ft1.type and
    ft2.distance <= ft1.distance
    limit 3, 1
)

EDIT: Better try this:

select id, type, x, y
from fruit_trees as ft1
where id in (
    select id
    from fruit_trees as ft2
    where 
    ft2.type = ft1.type
    order by ft2.distance
    limit 3
)

I have no MySQL available at the moment so i cannot test that query.

gpeche
Well the "ft2.distance" has to be calculated dynamically since the position of XY changes as the farmer walks around. I replaced the "ft2.distance" with this "SQRT(POW(ABS(5 - ft2.x),2) + POW(ABS(3 - ft2.y),2))". Would this work or do I have to store this calculation as a temp column?
Pawel
Also, we can't write the sub-query like that because we get a error from MySQL. "Unsupported subquery syntax error" as described in http://dev.mysql.com/doc/refman/5.0/en/subquery-errors.html
Pawel
In that same page there is a post by Frank Heikens on February 23 2008 5:01pm that explains a possible workaround for unsupported LIMIT
gpeche
+1  A: 

You can simulate row numbering with variables.

SELECT @i:=0, @type:=''
;

SELECT
      id, type, x, y
FROM (
    SELECT
          id, type, x, y
        , SQRT( POW(ABS(5 - x),2) + POW(ABS(3 - y),2) ) AS distance
        , IF( type=@type, @i:=@i+1, @i:=0             ) AS rank
        , IF( type=@type, @type,    @type:=type       ) AS new_type

    FROM
        fruit_trees
    ORDER BY
          type
        , distance
    ) x
WHERE
    rank < 3

Seems to work for me, but I expect performance will be ropey.

martin clayton
It works! Awesome. Any recommendations on improving performance?
Pawel