1. 程式人生 > 資訊 >平臺根據演算法處罰違規使用者,法院判了

平臺根據演算法處罰違規使用者,法院判了

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