PLZ Umkreissuche

Folgende Dateien müssen von http://www.fa-technik.adfc.de/code/opengeodb/ geladen werden:

  • opengeodb-begin.sql
  • opengeodb-end.sql
  • DE.sql
  • DEhier.sql


Darin muss folgendes ersetzt werden:

  • opengeodb-begin.sql
    • "TYPE=InnoDB" -> "ENGINE=InnoDB"
  • DE.sql
    • ",0,null,'" -> ",null,null,'" (sollte nur für die Tabelle geodb_floatdata sein)


Weiter muss der Primary Key in der Tabelle geodb_locations entfernt werden:

ALTER TABLE geodb_locations DROP PRIMARY KEY;


Danach können die Daten importiert werden (DAUERT!):

mysql -u root -p DATABASE < opengeodb-begin.sql
mysql -u root -p DATABASE < DE.sql
mysql -u root -p DATABASE < DEhier.sql
mysql -u root -p DATABASE < opengeodb-end.sql


Bevor es nun ans PHP-Script geht, muss wie auf OpenGeoDB - Umkreissuche beschrieben, die Tabelle zip_coordinates erstellt werden:

CREATE TABLE `geodb_zip_coordinates` (
    zc_id INT NOT NULL auto_increment PRIMARY KEY,
    zc_loc_id INT NOT NULL ,
    zc_zip VARCHAR( 10 ) NOT NULL ,
    zc_location_name VARCHAR( 255 ) NOT NULL ,
    zc_lat DOUBLE NOT NULL ,
    zc_lon DOUBLE NOT NULL
);

INSERT INTO geodb_zip_coordinates (zc_loc_id, zc_zip, zc_location_name, zc_lat, zc_lon)
SELECT gl.loc_id, plz.text_val, name.text_val, coord.lat, coord.lon
FROM geodb_textdata plz
LEFT JOIN geodb_textdata name     ON plz.loc_id = name.loc_id
LEFT JOIN geodb_locations gl      ON plz.loc_id = gl.loc_id
LEFT JOIN geodb_hierarchies tier  ON plz.loc_id = tier.loc_id
LEFT JOIN geodb_coordinates coord ON plz.loc_id = coord.loc_id
WHERE plz.text_type  = 500300000 /* Postleitzahl */
AND   name.text_type = 500100000 /* Name */
AND   tier.id_lvl1 = 104
AND   tier.id_lvl2 = 105 /* Bundesrepublik Deutschland */
AND   name.text_locale = "de" /* deutschsprachige Version */
AND   gl.loc_type IN ( 100600000 /* pol. Gliederung */, 100700000 /* Ortschaft */ );


Zum Schluss das benötigte PHP-Script:

<?php
public function searchForZipCodes($sourceZipCodes, $distance)
{
	$resultingZipCodes = [];
	$resultingData = [];

	$connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('geodb_zip_coordinates');
	
	foreach ($sourceZipCodes as $sourceZipCode) {
		$row = $connection->executeQuery('select zc_id from geodb_zip_coordinates where zc_zip = :zCode', 
										 ['zCode' => $sourceZipCode])
										->fetch();

		$zipList = $connection->executeQuery("SELECT
											  dest.zc_zip,
											  dest.zc_location_name,
											  ACOS(
												   SIN(RADIANS(src.zc_lat)) * SIN(RADIANS(dest.zc_lat))
												   + COS(RADIANS(src.zc_lat)) * COS(RADIANS(dest.zc_lat))
												   * COS(RADIANS(src.zc_lon) - RADIANS(dest.zc_lon))
											  ) * 6380 AS distance
											  FROM geodb_zip_coordinates dest
											  CROSS JOIN geodb_zip_coordinates src
											  WHERE src.zc_id = :zID
											  AND dest.zc_id <> src.zc_id
											  HAVING distance < :dist
											  ORDER BY distance;",
											['zID' => $row['zc_id'], 'dist' => $distance])
											->fetchAll();

		foreach ($zipList as $zipResult) {
			if (!in_array($zipResult['zc_zip'], $resultingZipCodes)) {
				$resultingZipCodes[] = $zipResult['zc_zip'];
				$resultingData[] = ['zip' => $zipResult['zc_zip'], 
									'locationName' => $zipResult['zc_location_name'], 
									'distance' => number_format($zipResult['distance'], 2)];
			}
		}
	}

	return $resultingData;
}

searchForZipCodes([59302,50667,38855,57271,38518,23730], 30);

Launix

Die OpenGeoDB hat sich leider als nicht so gut herausgestellt,
die Postleitzahlen für Düsseldorf haben z.B. alle die gleiche Position.

Bei der Suche nach einer neuen DB, bin ich auf die PLZ-DB von Launix gestoßen, welche alle Kriterien erfüllt.