source: trunk/import/pp_laden.sql @ 294

Revision 278, 13.8 KB checked in by frank.jaeger, 11 years ago (diff)

Mapbender-Navigation mit ALKIS-Daten komplett überarbeitet.

Line 
1
2-- ALKIS PostNAS 0.7
3
4-- Post Processing (pp_) Teil 2: Laden der Tabellen
5
6-- Stand
7
8--  2012-02-13 PostNAS 07, Umbenennung
9--  2012-02-17 Optimierung
10--  2012-04-17 Flurstuecksnummern auf Standardposition
11--  2012-04-24 Generell Filter 'endet IS NULL' um historische Objekte auszublenden
12--  2012-04-25 Abstürze und Fehler (durch kaputte Geometrie?) beim Zusammenfassen der Flächen
13--  2012-10-29 F.J. Redundanzen aus alkis_beziehungen beseitigen, die nach NAS replace auftreten
14--  2013-02-06 A.E. Function-Name an PostGIS 2 angepasst: multi() -> st_multi(), simplify() -> st_simplify()
15--  2013-02-21 F.J. doppelte Buchungen zum Flurstück aus alkis_beziehungen beseitigen, die nach NAS replace auftreten
16
17-- ============================
18-- Tabellen des Post-Processing
19-- ============================
20
21-- Einige Informationen liegen nach der NAS-Konvertierung in der Datenbank "verstreut" vor.
22-- Die dynamische Aufbereitung über Views und Functions würde zu lange dauern und somit lange
23-- Antwortzeiten in WMS, WFS, Buchauskunft oder Navigation (Suche) verursachen.
24
25-- Im Rahmen eines "Post-Processing" werden diese Daten nach jeder Konvertierung (NBA-Aktualisierung)
26-- einmal komplett aufbereitet. Die benötigten Informationen stehen somit den Anwendungen mundgerecht zur Verfügung.
27
28-- Die per PostProcessing gefüllten Tabellen bekommen den Profix "pp_".
29
30-- Die Ausführung dieses Scriptes auf einer Datenbank für eine 80T-Einwohner-Stadt dauert ca.: 500 Sek. !
31
32SET client_encoding = 'UTF-8';
33
34
35-- ============================================================================
36-- Redundanzen aus alkis_beziehungen beseitigen, die nach NAS replace auftreten
37-- ============================================================================
38-- Workaround: alle Redundazen nach einem Lauf entfernen.
39-- Besser wäre: sofort im Trigger bei replace entfernen.
40-- Siehe Schema in FUNCTION delete_feature_kill
41
42DELETE
43  FROM alkis_beziehungen AS bezalt        -- Beziehung Alt
44 WHERE EXISTS
45       (SELECT ogc_fid
46         FROM alkis_beziehungen AS bezneu -- Beziehung Neu
47        WHERE bezalt.beziehung_von = bezneu.beziehung_von
48          AND bezalt.beziehung_zu  = bezneu.beziehung_zu
49          AND bezalt.beziehungsart = bezneu.beziehungsart
50          AND bezalt.ogc_fid       < bezneu.ogc_fid
51        );
52-- Denkbar ist eine Variante für den Trigger, die zusätzlich
53-- auf eine bestimmte gml_id filtert.
54-- Damit wäre die DB schon während der Konvertierung konsistenter.
55-- Nachtrag 2013-02-20:
56-- Diese provisorische Lösung korrigiert nur die Fälle, wo ein Replace eine redundante Beziehung
57-- einträgt. Wenn ein Objekt und seine Beziehung gleichzeitig geändert wird, wird der alte
58-- Eintrag nicht gefunden und verbleibt in den Beziehungen.
59-- Siehe z.B. in Datei "sichten.sql" die Abfrage "mehrfache_buchung_zu_fs"
60
61
62-- Mehrfache Buchungen zu einem Flurstück korrigieren.
63-- Neu 2013-02-21
64-- Dieser Fehler enststeht, wenn ein Replace zu "ax_flurstueck" gleichzeitig die
65-- Beziehung 'istGebucht' zu "ax_buchungsStelle" ändert.
66-- Kann entfallen, sobald PostNAS bei Replace die "alkis_beziehungen" richtig fortführt.
67
68-- Version Marvin Brandt, Unna
69--      DELETE
70--      --  SELECT *
71--      FROM alkis_beziehungen a1
72--      WHERE a1.beziehung_von = ANY(SELECT gml_id FROM (
73--                              SELECT f.*,
74--                                              (SELECT count(f2.gml_id) as anzahl
75--                                              FROM ax_flurstueck f2
76--                                              JOIN alkis_beziehungen a1 ON f2.gml_id = a1.beziehung_von AND a1.beziehungsart = 'istGebucht'
77--                                              WHERE f2.gml_id = f.gml_id
78--                                              ) as anzahl
79--                                      FROM ax_flurstueck f
80--                                      ) as sub
81--                              WHERE sub.anzahl > 1 )
82--      AND a1.beziehungsart = 'istGebucht'
83--      AND a1.ogc_fid = (SELECT min(sub.ogc_fid) as ogc_fid FROM (
84--              SELECT a1.*,
85--                      (SELECT count(f2.gml_id) as anzahl
86--                              FROM ax_flurstueck f2
87--                              JOIN alkis_beziehungen a1 ON f2.gml_id = a1.beziehung_von AND a1.beziehungsart = 'istGebucht'
88--                              WHERE f2.gml_id = f.gml_id
89--                      ) as anzahl
90--              FROM ax_flurstueck f
91--              JOIN alkis_beziehungen a1
92--              ON f.gml_id = a1.beziehung_von AND a1.beziehungsart = 'istGebucht'
93--              ) as sub
94--      WHERE sub.beziehung_von = a1.beziehung_von);
95
96
97-- Version Frank Jäger, Lemgo
98DELETE
99-- SELECT *   -- TEST: erst mal schauen, was gelöscht würde, wenn ...
100FROM alkis_beziehungen b
101WHERE b.beziehungsart = 'istGebucht'
102  -- Die erste subquery zählt die Buchungen zu einer (Flurstücks-) gml_id.
103  -- Es wird nur dort gelöscht, wo mehrerer Buchungen existieren.
104  AND 1 <
105     ( SELECT count(f1.ogc_fid) AS anzfs
106        FROM ax_flurstueck f1
107        JOIN alkis_beziehungen z
108          ON f1.gml_id = z.beziehung_von
109       WHERE f1.gml_id = b.beziehung_von
110         AND z.beziehungsart = 'istGebucht'
111       GROUP BY f1.gml_id )
112  -- Die zweite Subquery liefert die letzte (= aktuelle) Beziehung.
113  -- Diese aktuelle Buchung wird vom Löschen ausgeschlossen.
114  AND b.ogc_fid <
115     ( SELECT max(a.ogc_fid) AS maxi
116        FROM ax_flurstueck f2
117        JOIN alkis_beziehungen a
118          ON f2.gml_id = a.beziehung_von
119       WHERE f2.gml_id = b.beziehung_von
120         AND a.beziehungsart = 'istGebucht'
121       GROUP BY a.beziehung_von )
122-- bei Test mit SELECT darf man sortieren:
123--  ORDER BY b.beziehung_von, b.ogc_fid
124;
125
126
127
128-- SELECT *
129--  FROM alkis_beziehungen AS bezalt
130--  WHERE EXISTS
131--        (SELECT ogc_fid
132--          FROM alkis_beziehungen AS bezneu
133--         WHERE bezalt.beziehung_von = bezneu.beziehung_von
134--           AND bezalt.beziehung_zu  = bezneu.beziehung_zu
135--           AND bezalt.beziehungsart = bezneu.beziehungsart
136--           AND bezalt.ogc_fid       < bezneu.ogc_fid
137--         );
138
139-- SELECT *
140--  FROM alkis_beziehungen AS bezalt
141--  WHERE EXISTS
142--        (SELECT ogc_fid
143--          FROM alkis_beziehungen AS bezneu
144--         WHERE bezalt.beziehung_von = bezneu.beziehung_von
145--           AND bezalt.beziehung_zu  = bezneu.beziehung_zu
146--           AND bezalt.beziehungsart = bezneu.beziehungsart
147--           AND bezalt.ogc_fid       < bezneu.ogc_fid
148--         )
149--      -- mit dem Zusatz nur die Faelle aus dem letzten Durchlauf,
150--      -- die aktuell noch in der Delet-Tabelle stehen
151--      AND EXISTS
152--         (SELECT ogc_fid
153--          FROM delete
154--          WHERE bezalt.beziehung_von = substr(featureid, 1, 16)
155--             OR bezalt.beziehung_zu  = substr(featureid, 1, 16)
156--         );
157
158
159-- =================================
160-- Flurstuecksnummern-Label-Position
161-- =================================
162
163-- ersetzt den View "s_flurstueck_nr" für WMS-Layer "ag_t_flurstueck"
164
165--DELETE FROM pp_flurstueck_nr;
166  TRUNCATE pp_flurstueck_nr;    -- effektiver als DELETE
167
168  INSERT INTO pp_flurstueck_nr
169          ( fsgml, fsnum, the_geom )
170    SELECT f.gml_id,
171           f.zaehler::text || COALESCE ('/' || f.nenner::text, '') AS fsnum,
172           p.wkb_geometry  -- manuelle Position des Textes
173      FROM ap_pto             p
174      JOIN alkis_beziehungen  v  ON p.gml_id       = v.beziehung_von
175      JOIN ax_flurstueck      f  ON v.beziehung_zu = f.gml_id
176     WHERE v.beziehungsart = 'dientZurDarstellungVon'
177       AND f.endet IS NULL
178       AND p.endet IS NULL
179     --AND p."art" = 'ZAE_NEN'
180   UNION
181    SELECT f.gml_id,
182           f.zaehler::text || COALESCE ('/' || f.nenner::text, '') AS fsnum,
183           ST_PointOnSurface(f.wkb_geometry) AS wkb_geometry  -- Flaechenmitte als Position des Textes
184      FROM      ax_flurstueck     f
185      LEFT JOIN alkis_beziehungen v  ON v.beziehung_zu = f.gml_id
186     WHERE v.beziehungsart is NULL
187       AND f.endet IS NULL
188  ;
189-- Ausführung: mittlere Stadt: ca. 4 - 18 Sec.
190
191
192-- ========================================================
193-- Tabellen fuer die Zuordnung vom Gemarkungen zu Gemeinden
194-- ========================================================
195
196-- Für die Regelung der Zugriffsberechtigung einer Gemeindeverwaltung auf die
197-- Flurstücke in ihrem Gebiet braucht man die Information, in welcher Gemeinde eine Gemarkung liegt.
198-- 'ax_gemeinde' und 'ax_gemarkung' haben aber im ALKIS keinerlei Beziehung zueinander - kaum zu glauben!
199-- Nur über die Auswertung der Flurstücke kann man die Zuordnung ermitteln.
200-- Da nicht ständig mit 'SELECT DISTINCT' sämtliche Flurstücke durchsucht werden können,
201-- muss diese Information als (redundante) Tabelle nach dem Laden zwischengespeichert werden.
202
203
204-- G E M A R K U N G
205
206--DELETE FROM pp_gemarkung;
207  TRUNCATE pp_gemarkung;
208
209-- Vorkommende Paarungen Gemarkung <-> Gemeinde in ax_Flurstueck
210INSERT INTO pp_gemarkung
211  (               land, regierungsbezirk, kreis, gemeinde, gemarkung       )
212  SELECT DISTINCT land, regierungsbezirk, kreis, gemeinde, gemarkungsnummer
213  FROM            ax_flurstueck
214  WHERE           endet IS NULL
215  ORDER BY        land, regierungsbezirk, kreis, gemeinde, gemarkungsnummer
216;
217
218-- Namen der Gemarkung dazu als Optimierung bei der Auskunft
219UPDATE pp_gemarkung a
220   SET gemarkungsname =
221   ( SELECT b.bezeichnung
222     FROM    ax_gemarkung b
223     WHERE a.land=b.land
224       AND a.gemarkung=b.gemarkungsnummer
225       AND b.endet IS NULL
226   );
227
228
229-- G E M E I N D E
230
231--DELETE FROM pp_gemeinde;
232  TRUNCATE pp_gemeinde;
233
234-- Vorkommende Gemeinden aus den gemarkungen
235INSERT INTO pp_gemeinde
236  (               land, regierungsbezirk, kreis, gemeinde)
237  SELECT DISTINCT land, regierungsbezirk, kreis, gemeinde
238  FROM            pp_gemarkung
239  ORDER BY        land, regierungsbezirk, kreis, gemeinde
240;
241
242
243-- Namen der Gemeinde dazu als Optimierung bei der Auskunft
244UPDATE pp_gemeinde a
245   SET gemeindename =
246   ( SELECT b.bezeichnung
247     FROM    ax_gemeinde b
248     WHERE a.land=b.land
249       AND a.regierungsbezirk=b.regierungsbezirk
250       AND a.kreis=b.kreis
251       AND a.gemeinde=b.gemeinde
252       AND b.endet IS NULL
253   );
254
255
256-- ==============================================================================
257-- Geometrien der Flurstücke schrittweise zu groesseren Einheiten zusammen fassen
258-- ==============================================================================
259
260-- Dies macht nur Sinn, wenn der Inhalt der Datenbank einen ganzen Katasterbezirk enthält.
261-- Wenn ein Gebiet durch geometrische Filter im NBA ausgegeben wurde, dann gibt es Randstreifen,
262-- die zu Pseudo-Fluren zusammen gefasst werden. Fachlich falsch!
263
264-- Ausführungszeit: 1 mittlere Stadt mit ca. 14.000 Flurstücken > 100 Sek
265
266-- ToDo:
267--   Nur "geprüfte Flurstücke" verwenden?  Filter?
268
269--   070: TopologyException: found non-noded intersection between   ...
270
271
272DELETE FROM pp_flur;
273
274INSERT INTO pp_flur (land, regierungsbezirk, kreis, gemarkung, flurnummer, anz_fs, the_geom )
275   SELECT  f.land, f.regierungsbezirk, f.kreis, f.gemarkungsnummer as gemarkung, f.flurnummer,
276           count(gml_id) as anz_fs,
277           st_multi(st_union(st_buffer(f.wkb_geometry,0.05))) AS the_geom -- 5 cm Zugabe um Zwischenräume zu vermeiden
278     FROM  ax_flurstueck f
279     WHERE f.endet IS NULL
280  GROUP BY f.land, f.regierungsbezirk, f.kreis, f.gemarkungsnummer, f.flurnummer;
281
282-- Geometrie vereinfachen, auf 1 Meter glätten
283UPDATE pp_flur SET simple_geom = st_simplify(the_geom, 1.0);
284
285
286-- Fluren zu Gemarkungen zusammen fassen
287-- -------------------------------------
288
289-- FEHLER: 290 Absturz PG! Bei Verwendung der ungebufferten präzisen Geometrie. 
290-- bufferOriginalPrecision failed (TopologyException: unable to assign hole to a shell), trying with reduced precision
291-- UPDATE: ../../source/headers/geos/noding/SegmentString.h:175: void geos::noding::SegmentString::testInvariant() const: Zusicherung »pts->size() > 1« nicht erfüllt.
292
293
294-- Flächen vereinigen (aus der bereits vereinfachten Geometrie)
295UPDATE pp_gemarkung a
296  SET the_geom =
297   ( SELECT st_multi(st_union(st_buffer(b.simple_geom,0.1))) AS the_geom -- noch mal 10 cm Zugabe
298     FROM    pp_flur b
299     WHERE a.land      = b.land
300       AND a.gemarkung = b.gemarkung
301   );
302
303-- Fluren zaehlen
304UPDATE pp_gemarkung a
305  SET anz_flur =
306   ( SELECT count(flurnummer) AS anz_flur
307     FROM    pp_flur b
308     WHERE a.land      = b.land
309       AND a.gemarkung = b.gemarkung
310   ); -- Gemarkungsnummer ist je BundesLand eindeutig
311
312-- Geometrie vereinfachen (Wirkung siehe pp_gemarkung_analyse)
313UPDATE pp_gemarkung SET simple_geom = st_simplify(the_geom, 8.0);
314
315
316-- Gemarkungen zu Gemeinden zusammen fassen
317-- ----------------------------------------
318
319-- Flächen vereinigen (aus der bereits vereinfachten Geometrie)
320UPDATE pp_gemeinde a
321  SET the_geom =
322   ( SELECT st_multi(st_union(st_buffer(b.simple_geom,0.1))) AS the_geom -- noch mal Zugabe 10 cm
323     FROM    pp_gemarkung b
324     WHERE a.land     = b.land
325       AND a.gemeinde = b.gemeinde
326   );
327
328-- Gemarkungen zählen
329UPDATE pp_gemeinde a
330  SET anz_gemarkg =
331   ( SELECT count(gemarkung) AS anz_gemarkg
332     FROM    pp_gemarkung b
333     WHERE a.land     = b.land
334       AND a.gemeinde = b.gemeinde
335   );
336
337-- Geometrie vereinfachen (Wirkung siehe pp_gemeinde_analyse)
338UPDATE pp_gemeinde SET simple_geom = st_simplify(the_geom, 20.0);
339
340
341-- =======================================================
342-- Tabelle fuer die Zuordnung vom Eigentümern zu Gemeinden
343-- =======================================================
344
345
346-- erst mal sauber machen
347DELETE FROM gemeinde_person;
348
349-- alle direkten Buchungen mit View ermitteln und in Tabelle speichern
350-- Für eine Stadt: ca. 20 Sekunden
351INSERT INTO  gemeinde_person
352       (land, regierungsbezirk, kreis, gemeinde, person, buchtyp)
353 SELECT land, regierungsbezirk, kreis, gemeinde, person, 1
354   FROM gemeinde_person_typ1;
355
356
357-- noch die komplexeren Buchungen ergänzen (Recht an ..)
358-- Mit View ermitteln und in Tabelle speichern
359-- Für eine Stadt: ca. 10 Sekunden
360INSERT INTO  gemeinde_person
361       (  land,   regierungsbezirk,   kreis,   gemeinde,   person,  buchtyp)
362 SELECT q.land, q.regierungsbezirk, q.kreis, q.gemeinde, q.person,  2
363   FROM gemeinde_person_typ2 q   -- Quelle
364   LEFT JOIN gemeinde_person z   -- Ziel
365     ON q.person   = z.person    -- Aber nur, wenn dieser Fall im Ziel
366    AND q.land     = z.land
367    AND q.regierungsbezirk = z.regierungsbezirk
368    AND q.kreis    = z.kreis
369    AND q.gemeinde = z.gemeinde
370  WHERE z.gemeinde is Null;      -- ..  noch nicht vorhanden ist
371
372
373-- ENDE --
Note: See TracBrowser for help on using the repository browser.