2010-03-09 26 views
15

Tôi chỉ đang tìm kiếm các đề xuất về cách tốt nhất để làm điều này ...php/mysql zip code proximity search

Tôi cần tạo chức năng tìm kiếm "người dùng" trong bán kính 50 dặm mã zip. Tôi có bảng mã zip chứa tất cả các mã zip của Hoa Kỳ có vĩ độ/kinh độ nhưng tôi chỉ đang cố tìm ra cách tốt nhất để cấu trúc và truy vấn dữ liệu của tôi ...

Tôi có nên thêm cột vĩ độ/kinh độ hay không vào bảng người dùng và truy vấn nó cho tất cả người dùng trong phạm vi bán kính của mã zip đã cho? Hoặc tôi có nên truy vấn bảng mã zip cho tất cả các mã zip nằm trong bán kính sau đó truy vấn bảng người dùng cho tất cả người dùng có kết quả (mã zip) không? Hoặc là... ??? Tôi mở cửa cho bất kỳ lời đề nghị vào thời điểm này!

Cảm ơn!

+0

Bạn có thể thay đổi dấu kiểm câu trả lời được chấp nhận không? Cảm ơn! –

Trả lời

16

Đây là cách tốt nhất tôi đã tìm thấy. Tất nhiên nó sẽ yêu cầu bạn có tất cả các mã hóa/vĩ độ mã hóa của bạn được mã hóa trong cơ sở dữ liệu.

// get all the zipcodes within the specified radius - default 20 
function zipcodeRadius($lat, $lon, $radius) 
{ 
    $radius = $radius ? $radius : 20; 
    $sql = 'SELECT distinct(ZipCode) FROM zipcode WHERE (3958*3.1415926*sqrt((Latitude-'.$lat.')*(Latitude-'.$lat.') + cos(Latitude/57.29578)*cos('.$lat.'/57.29578)*(Longitude-'.$lon.')*(Longitude-'.$lon.'))/180) <= '.$radius.';'; 
    $result = $this->db->query($sql); 
    // get each result 
    $zipcodeList = array(); 
    while($row = $this->db->fetch_array($result)) 
    { 
     array_push($zipcodeList, $row['ZipCode']); 
    } 
    return $zipcodeList; 
} 

Bạn sẽ có thể chỉ cần bỏ chức năng này. Vượt qua giá trị $ lat và $ lon của mã zip bạn muốn bán kính, bao gồm bán kính tùy chọn và nhận danh sách mã zip quay lại.

Bạn có thể dễ dàng sửa đổi điều này để có được tất cả người dùng trong đó mã zip IN (radius_sql) và đưa người dùng danh sách của bạn trở lại.

Mã hóa hạnh phúc!

+1

Điều này sẽ là tuyệt vời nhưng làm thế nào bạn sẽ đề nghị đặt hàng chúng theo khoảng cách? – mike

+1

Vì vậy, cách duy nhất bạn có thể là nếu bạn so sánh địa chỉ (lat/lon) với các địa chỉ xung quanh (lat/lon). Điều đó đang được nói, bạn vẫn có thể đặt hàng cho chúng bằng cách gần nhất với mã zip xa nhất. Nhưng xin lưu ý, điều này sẽ chỉ chỉ định "khu vực" của mã zip, không nhất thiết phải gần với các địa chỉ khác. Tôi có thể nói thêm vào lựa chọn: (3958 * 3.1415926 * sqrt ((Latitude - '. $ Lat.') * (Latitude - '. $ Lat.') + Cos (Latitude/57.29578) * cos (' . $ lat. '/ 57.29578) * (Kinh độ -'. $ lon. ') * (Kinh độ -'. $ lon. '))/180) như LOC sau đó vào cuối ORDER BY LOC. –

+0

Chỉ để cho mọi người biết ... Điều tra dân số Hoa Kỳ có kết quả này ở đây: http://www.census.gov/tiger/tms/gazetteer/zips.txt – r109

2

Kiểm tra việc tìm kiếm sự gần gũi đặc trưng ở đây:

Using PHP/MySQL with Google Maps

Nếu dữ liệu của bạn trong các ký hiệu tương tự/chiếu/định dạng (bất cứ điều gì đó được gọi là), nó có thể làm việc cho bạn.

+2

Liên kết đã chết ... Và điều gì sẽ xảy ra nếu tôi chỉ có mã bưu điện .. không có thông tin Long-Lati – Umair

+0

404 L --I - Vui lòng cập nhật câu trả lời của bạn. – Chinmay235

+0

@Chinu điểm công bằng - nhưng có rất nhiều câu trả lời hay khác ở đây, tôi sẽ yêu cầu OP xóa dấu kiểm để tôi có thể xóa câu trả lời –

0

Vĩ độ/thời gian bạn có cho mỗi mã zip là một trung tâm địa lý cho mã zip đó, phải không? Vì vậy, nếu bạn lần đầu tiên tìm thấy mã zip với các trung tâm địa lý trong vòng 50 dặm, sau đó người dùng trong các mã zip, bạn có thể dễ dàng được với người dùng cũ hơn 50 dặm. Vì vậy, bạn sẽ hy sinh một số độ chính xác làm theo cách đó.

Nhưng nếu bạn có nhiều người dùng (nhiều hơn số mã zip), điều này sẽ nhanh hơn, vì trước tiên bạn sẽ truy vấn bảng mã zip nhỏ hơn. Và bạn có thể lập chỉ mục mã zip trong bảng người dùng, vì vậy việc tìm kiếm người dùng có mã zip cụ thể sẽ nhanh chóng.

Chỉ cần một số suy nghĩ! Vì vậy, nếu bạn đang mong đợi rất nhiều người dùng và bán kính 50 dặm không cần phải chính xác, tôi sẽ tìm thấy mã zip trong vòng 50 dặm, sau đó người dùng trong những mã zip.

3

http://www.micahcarrick.com/04-19-2005/php-zip-code-range-and-distance-calculation.html

Tôi thấy điều này rất tuyệt vời.

"truy vấn bảng mã zip cho tất cả các mã zip có nằm trong bán kính sau đó truy vấn bảng sử dụng cho tất cả những người sử dụng với kết quả (mã zip)"

Tôi thấy điều này là cách tốt nhất để làm trừ khi bạn cần đưa người dùng lên bản đồ google. Nếu bạn chỉ liệt kê những người sử dụng trong phạm vi số dặm, nó sẽ khá dễ dàng để truy vấn cơ sở dữ liệu (sử dụng lớp) để có danh sách các khóa, sau đó chọn tất cả người dùng trong các mã zip đó.

Select * from Users where zip_code IN (19125,19081,19107.........); 

Điều đó sẽ thực hiện.

+0

Sau khi chơi với mọi thứ một chút. Tôi nghĩ rằng đây sẽ là lựa chọn tốt nhất nhưng tôi không chắc chắn làm thế nào tôi sẽ đặt hàng kết quả cuối cùng (người dùng) theo khoảng cách .... và, đó là trang web tôi nhận được dữ liệu mã zip của tôi từ! ;) – mike

+0

đã hoạt động rất tốt! cảm ơn – ladieu

+0

Điều này có liên kết đã chết. – Ael

1

Tôi muốn cân nhắc việc giảm số lượng ứng cử viên có hình vuông bao quanh trước, sau đó lo lắng về bán kính là bước thứ hai. Bạn bắt đầu với tọa độ của mã bưu điện, sau đó tính toán dài/lat 50 dặm trong tất cả 4 hướng, sau đó chọn các ứng cử viên duy nhất trong hộp rằng việc sử dụng nhiều hơn đơn giản/ít hơn tiêu chuẩn. Nếu cơ sở người dùng của bạn được dàn trải tốt thì điều này làm giảm đáng kể số lượng ứng cử viên của bạn, sau đó bạn chỉ phải thực hiện phép toán khoảng cách vector để loại bỏ "các góc".

2

Bắt đầu ở đây nhưng lưu ý rằng các giải pháp không phải là rất nhanh:

PHP Zip Code Range and Distance Calculation

Bây giờ để làm cho nó nhanh chóng - chúng ta sẽ thay thế các tra cứu để sử dụng một chỉ số không gian :)

  1. Sử dụng MySQL

  2. Thêm cột vào cơ sở dữ liệu được gọi là vị trí và làm cho nó nhập POINT

  3. Hãy chắc chắn rằng nó chấp nhận null ngay bây giờ

  4. Run Query SQL sau

    UPDATE zip_code SET location = PointFromText(CONCAT('POINT(',lon,' ',lat,')'));

  5. Bây giờ, làm cho cột không chấp nhận null

  6. Thêm một chỉ số không gian cho cột vị trí

  7. Trong mã từ chuyên gia trên JECT thay thế các chức năng 'get_zips_in_range' như sau:

    function get_zips_in_range($zip, $range, $sort=1, $include_base) 
        { 
    
    
        // returns an array of the zip codes within $range of $zip. Returns 
        // an array with keys as zip codes and values as the distance from 
        // the zipcode defined in $zip. 
    
        $this->chronometer();      // start the clock 
    
        $details = $this->get_zip_point($zip); // base zip details 
        if ($details == false) return false; 
    
        // This portion of the routine calculates the minimum and maximum lat and 
        // long within a given range. This portion of the code was written 
        // by Jeff Bearer (http://www.jeffbearer.com). This significanly decreases 
        // the time it takes to execute a query. My demo took 3.2 seconds in 
        // v1.0.0 and now executes in 0.4 seconds! Greate job Jeff! 
    
        // Find Max - Min Lat/Long for Radius and zero point and query 
        // only zips in that range. 
        $lat = $details[0]; 
        $lon = $details[1]; 
    
        $return = array(); // declared here for scope 
    
        $first = true; 
        $radius = $range/69.172; 
        $boundary = "POLYGON(("; 
        for($i=0; $i <= 360; $i += 360/24) 
        { 
         if($first) 
         { 
          $first = false; 
         } 
         else 
         { 
          $boundary .= ', '; 
         } 
    
         $clon = $radius*cos(deg2rad($i)) + $lon; 
         $clat = $radius*sin(deg2rad($i)) + $lat; 
         $boundary .= "$clon $clat" ; 
        } 
    
        $boundary .= '))'; 
    
        $sql = "SELECT zip_code, city, county, state_name, state_prefix, area_code, time_zone, lat, lon FROM zip_code WHERE MBRContains(GeomFromText('$boundary'), location);"; 
    
        //echo $sql; 
        $r = mysql_query($sql); 
    
        if (!$r) { // sql error 
    
         $this->last_error = mysql_error(); 
         return false; 
    
        } else { 
    
         while ($row = mysql_fetch_row($r)) { 
    
          // loop through the results to get the milage from src 
          $dist = $this->calculate_mileage($details[0],$row[7],$details[1],$row[8]); 
          if ($this->units == _UNIT_KILOMETERS) $dist = $dist * _M2KM_FACTOR; 
          $return[str_pad($row[0].', '.$row[1], 5, "0", STR_PAD_LEFT)] = round($dist, $this->decimals); 
    
         } 
         mysql_free_result($r); 
        } 
    
        // sort array 
        switch($sort) 
        { 
         case _ZIPS_SORT_BY_DISTANCE_ASC: 
          asort($return); 
          break; 
    
         case _ZIPS_SORT_BY_DISTANCE_DESC: 
          arsort($return); 
          break; 
    
         case _ZIPS_SORT_BY_ZIP_ASC: 
          ksort($return); 
          break; 
    
         case _ZIPS_SORT_BY_ZIP_DESC: 
          krsort($return); 
          break; 
        } 
    
        $this->last_time = $this->chronometer(); 
    
        if (empty($return)) return false; 
        return $return; 
        } 
    
+0

Cuối cùng, tôi đã sử dụng Nhân sư và nó rất nhanh ... Cảm ơn! – mike

1

tôi lần đầu tiên sẽ thực hiện tìm kiếm cho tất cả các zipcodes trong bán kính của các mục tiêu. Sau đó so sánh tất cả các mã zip được trả về với mã zip của người dùng. Kéo ra những người dùng phù hợp.

Nó tìm ra zipcodes trong bán kính, thấy cuộc gọi MySQL này:

$query = 'SELECT zzip FROM ' . table . 
      ' WHERE (POW((69.1*(zlongitude-"' . 
      $long . '")*cos(' . $long . 
      '/57.3)),"2")+POW((69.1*(zlatitude-"' . 
      $lat . '")),"2"))<(' . $radius . 
      '*' . $radius . ')'; 

MySQL hiện tất cả các toán cho bạn.

Tôi tìm thấy một lớp có sử dụng điều này ở đây: http://www.nucleusdevelopment.com/code/do/zipcode

Hy vọng rằng sẽ giúp.

+1

tôi tin rằng 'cos ('. $ Long' trong dòng thứ ba phải là' cos ('. $ Lat' – yitwail