平臺根據演算法處罰違規使用者,法院判了
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