Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Có thể sử dụng SqlGeography với Linq to Sql không?

Nếu tất cả những gì bạn muốn làm với SqlGeography là các điểm theo dõi và tận dụng các chỉ số không gian của SQL Server 2008, như những người khác đã lưu ý, bạn có thể ẩn cột dữ liệu không gian của mình khỏi Linq to SQL và sử dụng UDF hoặc các thủ tục được lưu trữ. Giả sử rằng bạn có một bảng AddressFields bao gồm các trường Latitude và Longitude. Thêm bảng đó vào tệp DBML của bạn và viết bất kỳ mã nào bạn muốn để đặt các trường Kinh độ và Vĩ độ. Sau đó, mã SQL bên dưới sẽ thêm trường Địa lý địa lý vào bảng đó và tạo trình kích hoạt trong cơ sở dữ liệu tự động đặt trường Địa lý dựa trên trường Vĩ độ và Kinh độ. Trong khi đó, đoạn mã dưới đây cũng tạo ra các UDF hữu ích khác và các thủ tục được lưu trữ:DistanceBetween2 (Tôi đã có một DistanceBetween) trả về khoảng cách giữa địa chỉ được thể hiện trong AddressField và một cặp vĩ độ / kinh độ được chỉ định; DistanceWithin trả về các trường khác nhau từ tất cả các Trường Địa chỉ trong khoảng cách một dặm được chỉ định; UDFDistanceWithin hoạt động giống như một hàm do người dùng xác định (hữu ích nếu bạn muốn nhúng hàm này vào một truy vấn lớn hơn); và UDFNearestNeighbors trả về các trường từ AddressField tương ứng với số lượng hàng xóm được chỉ định gần một điểm cụ thể. (Một lý do để sử dụng UDFNearestNeighbors là SQL Server 2008 sẽ không tối ưu hóa việc sử dụng chỉ mục không gian nếu bạn chỉ gọi thứ tự bằng cách gọi DistanceBetween2.)

Bạn sẽ cần tùy chỉnh điều này bằng cách thay đổi Trường địa chỉ thành bảng của bạn và tùy chỉnh các trường từ bảng đó mà bạn muốn trả về (xem mã xung quanh các tham chiếu đến AddressFieldID). Sau đó, bạn có thể chạy điều này trên cơ sở dữ liệu của mình và sao chép các thủ tục và UDF được lưu trữ kết quả vào DBML của bạn, sau đó bạn có thể sử dụng chúng trong các truy vấn. Nhìn chung, điều này cho phép bạn tận dụng chỉ số không gian của các điểm một cách khá dễ dàng.

-----------------------------------------------------------------------------------------

- [1]

--INITIAL AUDIT
select * from dbo.AddressFields
GO
--ADD COLUMN GEO
IF EXISTS (SELECT name FROM sysindexes WHERE name = 'SIndx_AddressFields_geo')
DROP INDEX SIndx_AddressFields_geo ON AddressFields
GO
IF EXISTS (SELECT b.name FROM sysobjects a, syscolumns b 
            WHERE a.id = b.id and a.name = 'AddressFields' and b.name ='Geo' and a.type ='U' )  
ALTER TABLE AddressFields DROP COLUMN Geo

GO
alter table AddressFields add Geo geography

- [2]

--SET GEO VALUE
GO
UPDATE AddressFields
SET Geo = geography::STPointFromText('POINT(' + CAST([Longitude] AS VARCHAR(20)) + ' ' + 
                    CAST([Latitude] AS VARCHAR(20)) + ')', 4326)

- [3] TẠO CHỈ SỐ

IF EXISTS (SELECT name FROM sysindexes WHERE name = 'SIndx_AddressFields_geo')
DROP INDEX SIndx_AddressFields_geo ON AddressFields

GO

CREATE SPATIAL INDEX SIndx_AddressFields_geo 
   ON AddressFields(geo)

--UPDATE STATS
UPDATE STATISTICS AddressFields

--AUDIT
GO
select * from dbo.AddressFields

- [4] TẠO THỦ TỤC USP_SET_GEO_VALUE PARA 1 LATITUDE 2 LONGITUDE

IF EXISTS (SELECT name FROM sysobjects  WHERE name = 'USPSetGEOValue' AND type = 'P')
    DROP PROC USPSetGEOValue
GO

GO
CREATE PROC USPSetGEOValue @latitude decimal(18,8), @longitude decimal(18,8)
AS
    UPDATE AddressFields
    SET Geo = geography::STPointFromText('POINT(' + CAST(@longitude AS VARCHAR(20)) + ' ' + 
                    CAST(@latitude AS VARCHAR(20)) + ')', 4326)
    WHERE [Longitude] [email protected] and [Latitude] = @latitude

GO
--TEST
EXEC USPSetGEOValue 38.87350500,-76.97627500

GO

- [5] TẠO TRIGGER TRÊN THAY ĐỔI / CHÈN GIÁ TRỊ LAT / DÀI ---> ĐẶT GEOCODE

IF EXISTS (SELECT name FROM sysobjects  WHERE name = 'TRGSetGEOCode' AND type = 'TR')
DROP TRIGGER TRGSetGEOCode

GO

CREATE TRIGGER TRGSetGEOCode 
ON AddressFields
AFTER INSERT,UPDATE
AS
    DECLARE @latitude decimal(18,8), @longitude decimal(18,8)

    IF ( UPDATE (Latitude) OR UPDATE (Longitude) )
        BEGIN

            SELECT @latitude = latitude ,@longitude = longitude from inserted

            UPDATE AddressFields
            SET Geo = geography::STPointFromText('POINT(' + CAST(@longitude AS VARCHAR(20)) + ' ' + 
                        CAST(@latitude AS VARCHAR(20)) + ')', 4326)
            WHERE [Longitude] [email protected] and [Latitude] = @latitude
        END 
    ELSE
        BEGIN
            SELECT @latitude = latitude ,@longitude = longitude from inserted

            UPDATE AddressFields
            SET Geo = geography::STPointFromText('POINT(' + CAST(@longitude AS VARCHAR(20)) + ' ' + 
                        CAST(@latitude AS VARCHAR(20)) + ')', 4326)
            WHERE [Longitude] [email protected] and [Latitude] = @latitude
        END 
GO

- [6] TẠO PROC USP_SET_GEO_VALUE_INITIAL_LOAD ----> CHỈ CHẠY MỘT LẦN

IF EXISTS (SELECT name FROM sysobjects  WHERE name = 'USPSetAllGeo' AND type = 'P')
    DROP PROC USPSetAllGeo
GO

CREATE PROC USPSetAllGeo
AS
UPDATE AddressFields
SET Geo = geography::STPointFromText('POINT(' + CAST([Longitude] AS VARCHAR(20)) + ' ' + 
                    CAST([Latitude] AS VARCHAR(20)) + ')', 4326)

GO

- [7] Khoảng cách PROC HIỆN TẠI, trả về khoảng cách giữa hai điểm được chỉ định

- theo cặp tọa độ vĩ độ / kinh độ. --ALTER PROC Khoảng cáchBetween2

IF EXISTS (SELECT name FROM sysobjects  WHERE name = 'DistanceBetween2' AND type = 'FN')
DROP FUNCTION DistanceBetween2

GO

CREATE FUNCTION [dbo].[DistanceBetween2] 
(@AddressFieldID as int, @Lat1 as real,@Long1 as real)
RETURNS real
AS
BEGIN

    DECLARE @KMperNM float = 1.0/1.852;

    DECLARE @nwi geography =(select geo from addressfields where AddressFieldID  = @AddressFieldID)

    DECLARE @edi geography = geography::STPointFromText('POINT(' + CAST(@Long1 AS VARCHAR(20)) + ' ' + 
                                CAST(@Lat1 AS VARCHAR(20)) + ')', 4326)

    DECLARE @dDistance as real = (SELECT (@nwi.STDistance(@edi)/1000.0) * @KMperNM)

    return (@dDistance);  

END

ĐI - KIỂM TRA

Khoảng cách giữa 2 12159,40.75889600, -73.99228900

- [8] TẠO THỦ TỤC USPDistanceWithin

- DANH SÁCH ĐỊA CHỈ TRỞ LẠI TỪ bảng AddressFields

NẾU TỒN TẠI (CHỌN tên TỪ sysobjects WHERE name ='USPDistanceWithin' AND type ='P') THỦ TỤC THẢ USPDistanceWithin

GO

CREATE PROCEDURE [dbo].USPDistanceWithin 
(@lat as real,@long as real, @distance as float)
AS
BEGIN

    DECLARE @edi geography = geography::STPointFromText('POINT(' + CAST(@Long AS VARCHAR(20)) + ' ' + 
                                CAST(@Lat AS VARCHAR(20)) + ')', 4326)

    SET @distance = @distance * 1609.344 -- convert distance into meter

    select 
         AddressFieldID
        ,FieldID
        ,AddressString
        ,Latitude
        ,Longitude
        ,LastGeocode
        ,Status
        --,Geo
    from 
        AddressFields a WITH(INDEX(SIndx_AddressFields_geo))
    where 
        a.geo.STDistance(@edi) < = @Distance 

END

ĐI

- THỬ NGHIỆM

- trong vòng 3 dặm USPDistanceWithin 38.90606200, -76.92943500,3GO - trong vòng 5 dặmUSPDistanceWithin 38.90606200, -76.92943500,5GO - trong vòng 10 dặmUSPDistanceWithin 38.90606200, -76.92943500,10

- [9] TẠO FUNCTION FNDistanceWithin

- DANH SÁCH ĐỊA CHỈ TRỞ LẠI TỪ bảng AddressFields

NẾU TỒN TẠI (CHỌN tên TỪ sysobjects WHERE name ='UDFDistanceWithin' AND type ='TF') CHỨC NĂNG DROP UDFDistanceWithin

GO

CREATE FUNCTION UDFDistanceWithin 
(@lat as real,@long as real, @distance as real)
RETURNS @AddressIdsToReturn TABLE 
    (
         AddressFieldID INT
        ,FieldID INT
    )
AS
BEGIN

    DECLARE @edi geography = geography::STPointFromText('POINT(' + CAST(@Long AS VARCHAR(20)) + ' ' + 
                                CAST(@Lat AS VARCHAR(20)) + ')', 4326)

    SET @distance = @distance * 1609.344 -- convert distance into meter

    INSERT INTO @AddressIdsToReturn
    select 
         AddressFieldID
        ,FieldID
    from 
        AddressFields a WITH(INDEX(SIndx_AddressFields_geo))
    where 
        a.geo.STDistance(@edi) < = @Distance 

    RETURN 

END

ĐI

- THỬ NGHIỆM

--Kithin 3 Milesselect * từ udfdistancewithin (38.90606200, -76.92943500,3) Go-within 5 milelect * từ udfdistancewithin (38.90603

- [9] TẠO CHỨC NĂNG UDFNearestNeighbors

- DANH SÁCH ĐỊA CHỈ TRỞ LẠI TỪ bảng AddressFields

NẾU TỒN TẠI (CHỌN tên TỪ sysobjects WHERE name ='UDFNearestNeighbors' AND type ='TF') CHỨC NĂNG DROP UDFNearestNeighbors

GO

NẾU TỒN TẠI (CHỌN tên TỪ sysobjects WHERE name ='number' AND xtype ='u') Số lượng trong BẢNG HIỆU QUẢ

GO
-- First, create a Numbers table that we will use below.
SELECT TOP 100000 IDENTITY(int,1,1) AS n INTO numbers FROM MASTER..spt_values a, MASTER..spt_values b CREATE UNIQUE CLUSTERED INDEX idx_1 ON numbers(n)

GO

CREATE FUNCTION UDFNearestNeighbors 
(@lat as real,@long as real, @neighbors as int)
RETURNS @AddressIdsToReturn TABLE 
    (
         AddressFieldID INT
        ,FieldID INT
    )
AS
BEGIN

    DECLARE @edi geography = geography::STPointFromText('POINT(' + CAST(@Long AS VARCHAR(20)) + ' ' + 
                                CAST(@Lat AS VARCHAR(20)) + ')', 4326)
    DECLARE @start FLOAT = 1000;

    WITH NearestPoints AS

    (

      SELECT TOP(@neighbors) WITH TIES *,  AddressFields.geo.STDistance(@edi) AS dist

      FROM Numbers JOIN AddressFields WITH(INDEX(SIndx_AddressFields_geo)) 

      ON AddressFields.geo.STDistance(@edi) < @start*POWER(2,Numbers.n)

      ORDER BY n

    )


    INSERT INTO @AddressIdsToReturn

    SELECT TOP(@neighbors)
         AddressFieldID
        ,FieldID
    FROM NearestPoints
    ORDER BY n DESC, dist

    RETURN 

END

ĐI

- THỬ NGHIỆM

--50 người hàng xóm chọn * từ UDFNearestNeighbors (38.90606200, -76.92943500,50) ĐI - 200 người hàng xóm chọn * từ UDFNearestNeighbors (38.90606200, -76.92943500.200) ĐI



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. 10 sự thật về giám sát hiệu suất cơ sở dữ liệu có thể khiến bạn ngạc nhiên

  2. Làm thế nào để thực thi một gói SSIS từ .NET?

  3. Toán tử logic HOẶC trong SQL Server là gì - Hướng dẫn sử dụng SQL Server / TSQL Phần 119

  4. Cách hiệu quả nhất trong SQL Server để lấy ngày từ ngày + giờ?

  5. Tương đương tốt nhất cho IsInteger trong SQL Server