【问题标题】:How to do trigger which create a point after insert longitude and latitude?如何在插入经度和纬度后触发创建点?
【发布时间】:2021-08-06 01:53:38
【问题描述】:

我想创建触发器,在将经度和纬度插入表车辆后,从经度纬度创建点。

我的触发器看起来是这样的

create trigger [dbo].[t_points]
on [dbo].[Vehicle]
after insert
as 
begin
SET NOCOUNT ON;
    DECLARE @Point AS GEOGRAPHY
    DECLARE @Longitude AS FLOAT
    DECLARE @Latitude AS FLOAT
        set @latitude = (select v.latitude from Vehicle v)
        set @longitude =    (select v.longitude from Vehicle v)

    if @latitude is not null and @Longitude is not null 
    begin
    set @Point = geography::Point(@latitude,@longitude,4326)
    update Vehicle set locationVehicle = @Point
    end
end
GO

但是当我插入我的表值时:

insert into Vehicle
  (idGroupVehicle, brand, model, maxRange, weight, maxSpeed, pricePerSale,
   latitude, longitude, locationName)
  values ('1', 'Xiaomi', 'Mijia M365 PRO', '45', '14', '1900', '25',
   '19.905203', '50.071597', 'Piastowska 49 Kraków')

我有错误

子查询返回超过 1 个值。当子查询跟随 =、!=、、>= 或子查询用作表达式时,这是不允许的。

谁能解释一下为什么我有这个错误,我不能在我的表中插入这个值我的触发器只检查纬度和经度不为空创建一个点。

【问题讨论】:

  • 为什么触发?只需创建一个计算列...最好使用persist。
  • 为什么你的触发器没有引用伪表inserted?另外,您的表Vehicle 真的只有一行吗?
  • 我认为您还没有掌握触发器的概念。您正在从Vehicle 的每一行中选择所有值,并实质上为每个@variable 分配一个随机值;然后,您将使用 @point 的值更新表中的所有行。 LocationVehicle 在这种情况下可能是一个计算列,无需尝试在触发器中重现基本相同的内容。

标签: sql-server tsql triggers geospatial spatial


【解决方案1】:

您必须查询Inserted 伪表以获取插入触发器中的插入行。此表可能会返回几行。您可以像这样更新位置列,而不是遍历行

CREATE TRIGGER [dbo].[t_points]
    ON [dbo].[Vehicle]
    AFTER INSERT
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE v
    SET
        v.locationVehicle = geography::Point(i.latitude, i.longitude, 4326)
    FROM
        dbo.Vehicle v
        INNER JOIN inserted i
            ON v.idVehicle = i.idVehicle
    WHERE
        i.latitude IS NOT NULL AND
        i.longitude IS NOT NULL

END

假设idGroupVehicle是表的主键。如果不是,则用主键替换(每个表都应该有一个主键)。

更新根据您的评论,我在连接中将idGroupVehicle 替换为idVehicle

【讨论】:

  • 我有自动增量,所以我的初级密钥是 idVehicle
  • 感谢朋友的帮助
【解决方案2】:

您的触发器存在根本缺陷:

  • 没有考虑到语句中可能有多个(或没有)行
  • 它没有引用inserted 伪表,因此它提取的数据来自随机行
  • 它正在写回整个表,因为没有where 过滤器

触发器看起来像这样:

create trigger [dbo].[t_points]
on [dbo].[Vehicle]
after insert
as 

SET NOCOUNT ON;

UPDATE v
SET locationVehicle = geography::Point(i.latitude, i.longitude,4326)
FROM inserted i
JOIN v ON v.id = i.id;  -- or whatever the primary key is

GO

但是:

一个更好的解决方案是一个简单的计算列:

ALTER TABLE Vehicle
    ADD locationVehicle AS (geography::Point(latitude, longitude, 4326));

【讨论】:

  • 我在我的表中有记录 locationVehicle 我想要触发,因为我在表 Customer 中执行相同的触发器,如果​​客户想在这个系统中注册客户将不必考虑如何输入他的点srid 必须使用
【解决方案3】:

我相信您的问题是您期望触发器的工作方式。

您收到的错误与触发器本身无关,您正在声明一个变量,然后尝试从子查询中为该变量分配一个值。

select v.latitude from Vehicle v - 这完全符合您的预期,在“触发器”内没有区别,它将返回一组值,实际上所有行都来自表 vehicle - 因此错误“返回多于一行” - 为变量赋值需要一个值。

要使用触发器执行此操作,无需为任何变量分配值。触发器的特别之处在于它提供了两个名为inserteddeleted虚拟 表,其中包含仅受发生的数据修改影响的行。您的插入可能已插入单行或多行,或者没有,并且只有这些行将在 inserted 表中。

要更新您的列受影响的行,您将执行以下操作

update v set
    v.LocationVehicle=geography::Point(v.latitude,v.longitude,4326)
from inserted i join Vehicle v on v.idGroupVehicle=i.idGroupVehicle

话虽如此,您可以尝试使用计算列来代替它来完成同样的事情

Alter table Vehicle add LocationVehicle as geography::Point(latitude,longitude,4326)

【讨论】:

    猜你喜欢
    • 2012-06-07
    • 2012-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多