更新触发器更新目标中的所有行,而不仅仅是更新?

时间:2012-06-10 19:39:57

标签: sql sql-server sql-server-2008 geospatial

我非常怀疑这个更新触发器正在更新目标上的所有行,而不仅仅是那些满足“更新(形状)”测试的行。性能很好'直到我添加第二个操作。单个空间连接发生得更快,这不是空间索引问题,此数据集中只有少数记录。

ALTER TRIGGER   [dbo].[GRSM_WETLANDS_Point_GIS_tbl_locations_update]
ON  [dbo].[GRSM_WETLANDS_POINT]
after update  
AS   
BEGIN   
  SET NOCOUNT ON;  
  if UPDATE (shape)
update GRSM_WETLANDS_Point
set X_Coord =CASE WHEN u.shape.STDimension() = 2 THEN u.shape.STCentroid().STX ELSE u.shape.STEnvelope().STCentroid().STX END,
    Y_Coord =CASE WHEN u.shape.STDimension() = 2 THEN u.shape.STCentroid().STY ELSE u.shape.STEnvelope().STCentroid().STY END
    from inserted i 
inner join GRSM_WETLANDS_POint u on i.GIS_Location_ID = u.GIS_Location_ID;
--second spatial operation
update GRSM_WETLANDS_Point
set QuadName = grsm.dbo.USGS_24K_TOPOMAP_BOUNDARIES.name 

FROM GRSM_WETLANDS_POint i
inner join grsm.dbo.USGS_24K_TOPOMAP_BOUNDARIES  
on i.GIS_Location_ID = i.GIS_Location_ID  
WHERE  (USGS_24K_TOPOMAP_BOUNDARIES.Shape.STContains(i.SHAPE) = 1) ;

end

我的怀疑是对的吗?

Upated:根据Aaron的建议......解决所有行问题。

update GRSM_WETLANDS_Point
set QuadName = grsm.dbo.USGS_24K_TOPOMAP_BOUNDARIES.name 
FROM inserted i inner join GRSM_WETLANDS_POint u on i.GIS_Location_ID = u.GIS_Location_ID
left outer join  grsm.dbo.USGS_24K_TOPOMAP_BOUNDARIES  
on i.GIS_Location_ID = i.GIS_Location_ID  
WHERE  (USGS_24K_TOPOMAP_BOUNDARIES.Shape.STContains(i.SHAPE) = 1); 

2 个答案:

答案 0 :(得分:3)

如果Shape不能为NULL,则查看其是否已更改的更好方法是检查inserteddeleted中的值是否不同。例如:

IF EXISTS
(
  SELECT 1 FROM inserted AS i
  INNER JOIN deleted AS d
  ON i.GIS_Location_ID = d.GIS_Location_ID
  WHERE i.Shape.STEquals(d.Shape) = 0
)
BEGIN
  ...
END

如果Shape可以为空,那么您只需在那里添加更多条件进行检查,例如

  WHERE 
  (
    (i.Shape IS NULL AND d.Shape IS NOT NULL
    OR (i.Shape IS NOT NULL AND d.Shape IS NULL)
    OR (i.Shape.STEquals(d.Shape) = 0)
  )

(您可能不在乎Shape是否已更新 NULL,我只是说明如何测试该案例。)

由于操作可能发生在多个行上,并且此条件只会识别至少发生过一次此类更新(但并非所有行都符合条件),因此最好让您的操作包含类似的条件。 WHERE子句。事实上,我认为您可以在一次操作中执行这两种更新,例如

ALTER TRIGGER [dbo].[GRSM_WETLANDS_Point_GIS_tbl_locations_update]
ON  [dbo].[GRSM_WETLANDS_POINT]
AFTER UPDATE
AS   
BEGIN   
  SET NOCOUNT ON; 

  UPDATE p SET 
    X_Coord = CASE WHEN i.shape.STDimension() = 2 
      THEN i.shape.STCentroid().STX 
      ELSE i.shape.STEnvelope().STCentroid().STX 
    END,
    Y_Coord = CASE WHEN i.shape.STDimension() = 2 
      THEN i.shape.STCentroid().STY 
      ELSE i.shape.STEnvelope().STCentroid().STY 
    END, 
    QuadName = COALESCE(b.name, p.QuadName)
  FROM 
    dbo.GRSM_WETLANDS_Point AS p
  INNER JOIN 
    inserted AS i
    ON i.GIS_Location_ID = p.GIS_Location_ID
  LEFT OUTER JOIN grsm.dbo.USGS_24K_TOPOMAP_BOUNDARIES AS b
    ON b.Shape.STContains(i.Shape) = 1
  WHERE EXISTS 
  (
    SELECT 1 FROM inserted AS i2
      INNER JOIN deleted AS d
      ON i2.GIS_Location_ID = d.GIS_Location_ID
      WHERE i2.GIS_Location_ID = i.GIS_Location_ID
      AND i2.Shape.STEquals(d.Shape) = 0
      -- ...and NULL handling if necessary
  );
END
GO

一般来说,你似乎在实现触发器方面遇到了很多麻烦,并且对语法应该如何工作做了很多猜测。您是否考虑过通过存储过程强制进行数据更新,您可以在其中控制所有这些业务逻辑,但消除了inserteddeleted伪表添加的复杂性?

答案 1 :(得分:2)

如果UPDATE(形状)即使值没有改变也会触发,如果更新语句中存在该列,它将触发

您未在第二次更新中加入INSERTED