Rasters, Pixels and Code Oh My!<\/A> habe ich einen Automatisierungs-Trigger erweitert, um ein Attributfeld basierend auf seiner Position innerhalb eines Rasterpixels zu füllen. Aber ich möchte noch mehr Datenautomatisierung. Ich will alles!<\/P>
Wir wollen nicht nur einige administrative Attribute neuer Datenpunkte wissen (in welchem Landkreis, Bundesstaat befindet er sich?: Spatial Intersect), wie hoch er ist, sondern in einer Ära von nicht ganz präzisen Datenpunkten, was ist dem Punkt am nächsten?<\/P>
<\/P>
In dieser speziellen Anwendung, einem Datensatz zur Wasserqualitätsüberwachung, möchte ich auch den Namen des Flusses wissen, auf dem dieser Punkt liegt, sowie die Flussordnung. Ich verwende NHD Stream Lines, die durch Arc Hydro gelaufen sind, um die Strahler Stream Order als Attribut hinzuzufügen.<\/P>
<\/P>
Mit einer Nearest Neighbor Query kann ich das erreichen, wenn auch mit etwas mehr Komplexität, da ich jetzt SQL bitte, das "Nearest" Feature zu suchen und nicht nur eine einfache Überschneidung zweier Geographie-Objekte. Der Codeblock beginnt in Zeile 48.<\/P>
<\/P>
<\/P>
<\/P>
ALTER TRIGGER [dbo].[TEST_GEOGRAPHY]
ON [dbo].[TEST]
\/****** feuert bei Inserts und Updates ******\/
\/****** deaktiviert Trigger wenn SQL Replikation oder Spiegelung aktiviert ist ******\/
after INSERT,UPDATE NOT FOR REPLICATION
AS
BEGIN
SET NOCOUNT ON;
UPDATE p SET
\/****** hypothetisch könnten wir lat\/lon als Text eingeben und ein Geography-Objekt erstellen ******\/
SHAPE = CASE WHEN i.SHAPE IS NOT NULL
THEN p.SHAPE ELSE Geography::STPointFromText('POINT('
+ CAST(p.LON AS VARCHAR(20)) + ' '
+ CAST(p.LAT AS VARCHAR(20)) + ')', 4269) END,
\/****** üblicherweise wird der Punkt mit ARC erstellt und castet LAT\/LON als Text ******\/
\/****** vom Geography-Objekt ******\/
LON = CASE WHEN p.SHAPE IS NULL THEN p.LON ELSE p.SHAPE.Long END,
LAT = CASE WHEN p.SHAPE IS NULL THEN p.LAT ELSE p.SHAPE.Lat END,
QuadName = COALESCE(b.name, p.QuadName),
Watershed = COALESCE(c.HUC_12_Name, p.Watershed),
County = COALESCE(d.Name, p.County),
State= COALESCE(e.Name, p.State),
PARKDISTRICT = COALESCE(f.District, p.PARKDISTRICT),
ELEVATION = (SELECT
pdata.getValueByLoc(1,p.SHAPE.Long,p.SHAPE.Lat) FROM [dbo].[DEM10MP]),
StreamName = COALESCE(g.GNIS_Name, p.StreamName),
RiverOrder = COALESCE(h.RiverOrder, p.RiverOrder)
FROM TEST
AS p
\/****** erlaubt Update von lat\/lon bei Update ******\/
INNER JOIN
inserted AS i
ON i.globalid = p.globalid
LEFT OUTER JOIN USGS_24K_TOPOMAP_BOUNDARIES AS b
ON b.Shape.STIntersects(i.Shape) = 1
LEFT OUTER JOIN WATERSHEDS AS c
ON c.Shape.STIntersects(i.Shape) = 1
LEFT OUTER JOIN GRSM_COUNTIES AS d
ON d.Shape.STIntersects(i.Shape) = 1
& nbsp ;& nbsp ;& nbsp ;& nbsp ;& nbsp ;& nbsp ;& nbsp ;& nbsp ;& nbsp ; LEFT OUTER JOIN GRSM_States AS e
ON e.Shape.STIntersects(i.Shape) = 1
LEFT OUTER JOIN GRSM_SUB_RANGER_DISTRICTS AS f
ON f.Shape.STIntersects(i.Shape) = 1
\/****** Nearest Neighbor ******\/
CROSS APPLY (SELECT TOP 1 GNIS_Name, shape&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;
FROM dbo.NHDFLOWLINE
\/****** erzwinge spatial index hint ******\/
WITH(index ([S208_idx]))
WHERE NHDFLOWLINE.Shape.STDistance(i.Shape) IS NOT NULL
ORDER BY NHDFLOWLINE.Shape.STDistance(i.Shape) ASC) as g
CROSS APPLY (SELECT TOP 1 RiverOrder, shape&amp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mp;a mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa mpa amp;
FROM dbo.NHDFLOWLINE
\/****** erzwinge spatial index hint ******\/
WITH(index ([S208_idx]))
WHERE NHDFLOWLINE.Shape.STDistance(i.Shape) IS NOT NULL
ORDER BY NHDFLOWLINE.Shape.STDistance(i.Shape) ASC) as h
;
END
GO<\/PRE><\/P>Beachte hier die Verwendung eines Index-Hints. In SQL 2008 wird die Verwendung des spatial index nicht berücksichtigt und funktioniert tatsächlich ohne viele Anpassungen nicht. Hier sagen wir ihm, den Namen des nächstgelegenen Flusses und dessen Ordnung zu finden, aber nutze den spatial index der NHD Flowline Feature-Klasse zur Optimierung der Abfrage. Ohne den Index-Hint dauert diese Abfrage ewig!<\/P><\/P>Wenn der Flussname null ist (wie bei vielen), stoppen die crossapply- und order by-Anweisungen die Suche beim nächstgelegenen Fluss anstatt nach dem nächstgelegenen benannten Fluss zu suchen.<\/P><\/P>Ich habe festgestellt, dass dies am besten funktioniert, wenn ich einige Dateneingaberegeln durchsetze: einen neuen Punkt nur mit Snapping hinzufügen (an die NHD-Ebene in der Kartenoberfläche). Es besteht die Gefahr, dass jemand versehentlich einen neuen Punkt hinzufügt, der "irgendwie" zwischen zwei Flüssen liegt und der falsche Name und die falsche Ordnung dem Punkt zugewiesen werden könnten.<\/P><\/P>In dieser speziellen Anwendung verwenden wir es zusammen mit den USGS HEM Tools, die das Snapping, die Zuordnung und das Befüllen des Reachcode für die Punktdaten übernehmen, sodass wir uns nicht allzu sehr über das Szenario "falscher Punkt am falschen Ort" sorgen müssen.<\/P><\/P>Dies ist ein persönlicher Blog und empfiehlt, befürwortet oder unterstützt nicht die oben beschriebenen Methoden. Die Änderung von Daten mit SQL außerhalb des ESRI Software-Stacks wird natürlich nicht unterstützt und sollte ohne gründliches Verständnis und Notfallwiederherstellungsplan nicht auf eine Produktionsdatenbank angewendet werden.<\/EM><\/P><\/BODY><\/HTML>