插入经纬度后如何触发创建点?

How to do trigger which create a point after insert longitude and latitude?

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

我的触发器看起来像

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

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

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')

我有错误

Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

有人能解释一下为什么我有这个错误而且我不能插入我的 table 这个值我的触发器只检查纬度和经度不为空创建一个点。

您必须查询 Inserted 伪 table 才能在插入触发器中获取插入的行。这 table 可能 return 多行。您可以像这样更新位置列,而不是遍历行

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是table的主键。如果不是,用主键替换它(每个table应该有一个主键)。

UPDATE 根据您的评论,我在连接中用 idVehicle 替换了 idGroupVehicle

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

  • 它没有考虑到语句中可能有多个(或没有)行
  • 它没有引用 inserted 伪 table,因此它提取的数据来自随机行
  • 它正在写回整个 table,因为没有 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));

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

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

select v.latitude from Vehicle v - 这完全符合您的预期,在“触发器”中没有区别,它将 return 一组值,所有行实际上来自 table vehicle - 因此错误“return 编辑了不止一行” - 为变量赋值需要一个值。

要使用触发器执行此操作,无需为任何变量赋值。触发器的特殊之处在于它使两个 virtual tables 可用,称为 inserteddeleted,其中包含仅受发生的数据修改影响的行.您的插入可能插入了一行或多行,或者 none,并且只有这些行会出现在 inserted table.

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

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)