mysql中geometry類型的簡單使用


mysql中geometry類型的簡單使用

編寫本文的目的:

    讓和兩天前的我一樣的初學者,能夠更快的使用geometry類型存儲空間點數據
    也是為了自己加深印象,更熟練的使用geometry類型

建表腳本

復制代碼
CREATE TABLE `z_gis` (
  `id` varchar(45) NOT NULL,
  `name` varchar(10) NOT NULL COMMENT '姓名',
  `gis` geometry NOT NULL COMMENT '空間位置信息',
  `geohash` varchar(20) GENERATED ALWAYS AS (st_geohash(`gis`,8)) VIRTUAL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`),
  SPATIAL KEY `idx_gis` (`gis`),
  KEY `idx_geohash` (`geohash`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='空間位置信息'
復制代碼

這里我創建了一張位置信息表,每個人對應的經緯度都會以geometry類型存在表中,geohash字段是把坐標系分成很多小方格,然后將經緯度轉化成字符串,其原理可自行百度,在這里就不多說了。
哦,對了,geometry類型好像不能為null,所以建表時必須為not null。
插入表數據

復制代碼
insert into z_gis(id,name,gis) values
(replace(uuid(),'-',''),'張三',ST_GeometryFromText('point(108.9498710632 34.2588125935)')),
(replace(uuid(),'-',''),'李四',ST_GeometryFromText('point(108.9465236664 34.2598766768)')),
(replace(uuid(),'-',''),'王五',ST_GeometryFromText('point(108.9477252960 34.2590342786)')),
(replace(uuid(),'-',''),'趙六',ST_GeometryFromText('point(108.9437770844 34.2553719653)')),
(replace(uuid(),'-',''),'小七',ST_GeometryFromText('point(108.9443349838 34.2595663206)')),
(replace(uuid(),'-',''),'孫八',ST_GeometryFromText('point(108.9473497868 34.2643456798)')),
(replace(uuid(),'-',''),'十九',ST_GeometryFromText('point(108.9530360699 34.2599476152)'));
復制代碼

名字是我隨便起的,不要噴我哦,經緯度是我在地圖上隨便取的點,geomfromtext()函數是將字符串格式的點坐標,轉化成geometry類型,還有個字段geohash是根據gis字段的值自動生成的,可以仔細看看建表腳本。
接下來是幾個簡單的查詢例子
1. 查詢張三的經緯度信息

select name, astext(gis) gis from z_gis where name = '張三';

    astext()函數是將geometry類型轉化為字符串

sql執行結果 

2. 修改張三的位置信息

update z_gis set gis = geomfromtext('point(108.9465236664 34.2598766768)') where name = '張三';

我用的Mysql Workbench工具,修改時報錯如下:

You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column To disable safe mode, toggle the option in Preferences -> SQL Editor and reconnect.


好像是除了用id修改,其他修改都會報這個錯,下面這樣設置一下就OK了 。

set sql_safe_updates = 0;

3. 查詢張三和李四之間的距離

select floor(st_distance_sphere(
    (select gis from z_gis where name= '張三'),
    gis
)) distance from z_gis where name= '李四';

    本來想格式化sql語句的,但是發現格式化之后的sql 基本全變成大寫的了,我覺得辨識度更低了,所有大家就這樣將就看吧,st_distance_sphere()函數是計算兩點之間距離的,所以傳兩個參數,都是geometry類型的,floor()函數是把計算出的距離取整。

sql執行結果 

4. 查詢距離張三500米內的所有人

復制代碼
SELECT
    name,
    FLOOR(ST_DISTANCE_SPHERE((SELECT
                            gis
                        FROM
                            z_gis
                        WHERE
                            name = '張三'),
                    gis)) distance,
                    astext(gis) point
FROM
    z_gis
WHERE
    ST_DISTANCE_SPHERE((SELECT
                    gis
                FROM
                    z_gis
                WHERE
                    name = '張三'),
            gis) < 500
        AND name != '張三';  
復制代碼

sql執行結果 

    如果表中數據非常多時,這樣查效率會非常低,這時就會用到geohash字段查詢

sql語句如下:

復制代碼
SELECT
    name,
    floor(ST_DISTANCE_SPHERE((SELECT
                    gis
                FROM
                    z_gis
                WHERE
                    name = '張三'),
            gis)) distance,
            astext(gis) point
FROM
    z_gis
WHERE
    geohash like concat(left((select geohash from z_gis where name = '張三'),6),'%')
          AND ST_DISTANCE_SPHERE((SELECT
                    gis
                FROM
                    z_gis
                WHERE
                    name = '張三'),
            gis) < 500
        AND name != '張三';  
復制代碼

    前面說過geohash是把經緯度轉成字符串,建表的時候我定義讓它轉成8位字符,當兩個點離得越近時,它生成的geohash字符串前面相同的位數越多,所以我在這里先用left()截取前6位字符,前6位相同的誤差在±600米左右,然后模糊查詢,查出大概符合條件的數據,最后再精確比較,下面是geohash官方文檔對geohash長度和距離誤差的說明:



    注意:用geohash 查詢會有邊界問題,所以查詢出來的結果又可能不准確,可以用程序(例如java代碼)先查出當前點周圍8個范圍的geohash值,然后再匹配這9個范圍的所有數據,這樣就解決了geohash 的邊界問題。

geohash官方文檔地址:https://en.wikipedia.org/wiki/Geohash

    之前沒用過markdown編輯器,所以文檔格式排版很亂,請大家見諒,上面有解釋不對的地方,也請大佬們及時指出來,畢竟我也算是小白,還有很多地方需要學習。
 
 轉自:https://blog.csdn.net/MinjerZhang/article/details/78137795 

 

 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM