问题
I have a function that which iterates "for each row" in the table. When it is run it should look at each row, pull in the related SET values for that row and run the function which in turns returns a result and updates the correct row with the correct value. What is happening is that it is running and returning the value for the very last row and updating all the row with that value. Any ideas what I'm doing wrong?
SELECT
RowNum = ROW_NUMBER() OVER(ORDER BY ID)
,*
INTO #Geo
FROM DDDG
DECLARE @MaxRownum INT
SET @MaxRownum = (SELECT MAX(RowNum) FROM #Geo)
DECLARE @Iter INT
SET @Iter = (SELECT MIN(RowNum) FROM #Geo)
WHILE @Iter <= @MaxRownum
BEGIN
SELECT *
FROM #Geo
WHERE RowNum = @Iter
DECLARE @address nvarchar (100);
Select @address = Ad1 from DDDG where id = @Iter;
DECLARE @state nvarchar (100);
SET @state = 'FL';
DECLARE @zip nvarchar (100);
SET @zip = '33142';
DECLARE @city nvarchar (100);
SET @city = 'Miami';
DECLARE @nation nvarchar (2);
SET @nation = 'us';
DECLARE @g geography;
WAITFOR DELAY '00:00:00.050'
SET @g = dbo.Geocode(@nation, @state, @city, @zip, @address);
Update DDDG
Set Lat = @g.Lat
where id = @Iter;
Update DDDG
Set long = @g.Long
where id = @Iter;
SET @Iter = @Iter + 1
END
DROP TABLE #Geo
Update .....
thanks all... I almost got it working.. After a hell of a lot of trial and error I figured out that I needed to change the following
Update DDDG Set Lat = @g.Lat where id = id;
Update DDDG Set long = @g.Long where id = id;
I only have one problem now. When I delete rows the RowNum and the @Iter no longer match up. is there a way of fixing this problem other than recreating the table every time?
回答1:
WITH CTE_DDD(ID,Ad1)
AS
(
SELECT ID, Ad1 FROM DDD
)
UPDATE d
SET d.lat = dbo.Geocode(@nation, @state, @city, @zip,Ad1).lat, long = dbo.Geocode(@nation, @state, @city, @zip,Ad1).long
FROM DDD d
WHERE d.id = ID
Modified Query after getting downvotes from peers for the above one:
WITH CTE_DDD AS
(
SELECT * FROM DDD
)
UPDATE CTE_DDD SET lat = (SELECT lat from dbo.Geocode(@nation, @state, @city, @zip,Ad)), long = (SELECT long from dbo.Geocode(@nation, @state, @city, @zip,Ad))
I would agree that CROSS APPLY is a better solution as it would call the function once per row.
回答2:
I may be missing something, but why do you need a loop at all?:
UPDATE DDDG
SET Lat = dbo.GeoCode('us','FL','Miami','33142',Ad1).Lat,
Long = dbo.GeoCode('us','FL','Miami','33142',Ad1).Long;
It is also possible to improve the query further by reducing the number of calls to dbo.GeoCode
to just one per row:
UPDATE t
SET Lat = g.GC.Lat,
Long = g.GC.Long
FROM DDDG AS t
CROSS APPLY (
SELECT dbo.GeoCode('us','FL','Miami','33142',Ad1) AS GC
) AS g;
来源:https://stackoverflow.com/questions/21559484/run-sql-server-function-against-each-row-in-table