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

Làm cách nào để xử lý các truy vấn chồng chéo đa giác MySQL?

SQL fiddle

Tạo bảng với cột đa giác

Xin lưu ý rằng để sử dụng chỉ mục không gian, bạn không thể sử dụng InnoDB. Bạn có thể sử dụng hình học mà không có chỉ mục không gian, nhưng hiệu suất sẽ giảm như bình thường.

CREATE TABLE IF NOT EXISTS `spatial` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `poly` geometry NOT NULL,
  UNIQUE KEY `id` (`id`),
  SPATIAL INDEX `poly` (`poly`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;

Lấy 3 hình vuông và một hình tam giác được chèn

INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0))',0));
INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((10 50,50 50,50 10,10 10,10 50))',0));
INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((1 15,5 15,5 11,1 11,1 15))',0));
INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((11 5,15 5,15 1,11 5))',0));

Chọn mọi thứ giao với hình vuông nhỏ ở góc dưới bên trái (hình vuông màu tím # 1)

SELECT id,AsText(poly) FROM  `spatial` 
    WHERE 
        ST_Intersects(`poly`,
            GEOMFROMTEXT('POLYGON((0 0,2 0,2 2,0 2,0 0))', 0 )
        )
;

Chọn mọi thứ giao nhau giữa hình tam giác, từ góc dưới bên trái sang góc dưới bên phải đến góc trên bên phải) (hình vuông # 1 và # 2 và hình tam giác # 4.)

SELECT id,AsText(poly) FROM  `spatial` 
    WHERE 
        ST_Intersects(`poly`,
            GEOMFROMTEXT('POLYGON((0 0,50 50,50 0,0 0))', 0 )
        )
;

Chọn mọi thứ trong hình vuông nằm ngoài hình ảnh của chúng tôi (không có gì)

SELECT id,AsText(poly) FROM  `spatial` 
    WHERE 
        ST_Intersects(`poly`,
            GEOMFROMTEXT('POLYGON((100 100,200 100,200 200,100 200,100 100))', 0 )
        )
;

Chỉnh sửa # 1:

Tôi đọc lại câu hỏi và tôi nghĩ rằng bạn có một chút nhầm lẫn giữa các mối quan hệ không gian. Nếu những gì bạn muốn là tìm mọi thứ vừa vặn bên trong một hình vuông (đa giác), thì bạn cần sử dụng Chứa / ST_Contains. Vui lòng xem các hàm không gian trong tài liệu MySQL để tìm hiểu chức năng nào phù hợp với bạn. Vui lòng lưu ý sự khác biệt sau đây giữa các chức năng ST / MBR:

Chọn mọi thứ nằm hoàn toàn bên trong hình vuông (# 0 từ bên dưới) (hình vuông # 1, # 2, hình tam giác # 4)

SELECT id,AsText(poly) FROM  `spatial` 
    WHERE 
        Contains(
          GEOMFROMTEXT('POLYGON((0 0,20 0,20 20,0 20,0 0))', 0 ),
          `poly`
        )
;

Chọn mọi thứ nằm hoàn toàn bên trong hình vuông (# 0 từ bên dưới) và không có cạnh (hình vuông # 2, hình tam giác # 4)

SELECT id,AsText(poly) FROM  `spatial` 
    WHERE 
        ST_Contains(
          GEOMFROMTEXT('POLYGON((0 0,20 0,20 20,0 20,0 0))', 0 ),
          `poly`
        )
;

Chỉnh sửa # 2:

Bổ sung rất hay từ @StephanB ( SQL fiddle )

Chọn bất kỳ đối tượng chồng chéo nào

SELECT s1.id,AsText(s1.poly), s2.id, AsText(s2.poly)
FROM  `spatial` s1, `spatial` s2
    WHERE 
        ST_Intersects(s1.poly, s2.poly)
    AND s1.id < s2.id
;

(chỉ cần lưu ý rằng bạn nên xóa AND s1.id < s2.id nếu bạn đang làm việc với CONTAINS , dưới dạng CONTAINS(a,b) <> CONTAINS(b,a) while Intersects(a,b) = Intersects(b,a) )

Trong hình sau (danh sách không đầy đủ):

  • 2 giao nhau # 6.

  • 6 giao nhau # 2

  • 0 giao với # 1, # 2, # 3, # 4, # 5

  • 1 giao với # 0, # 5

  • 0 chứa # 1, # 3, # 4 và # 5 (# 1, # 3, # 4 và # 5 nằm trong # 0)

  • 1 chứa # 5 (# 5 nằm trong # 1)

  • 0 st_contains # 3, # 4 và # 5

  • 1 st_contains # 5

Chỉnh sửa # 3:Tìm kiếm theo khoảng cách / Làm việc trong (với) vòng kết nối

MySQL không hỗ trợ trực tiếp hình tròn dưới dạng hình học, nhưng bạn có thể sử dụng hàm không gian Buffer(geometry,distance) để làm việc xung quanh nó. Cái gì Buffer() hiện đang tạo ra một vùng đệm của khoảng cách đã nói xung quanh hình học. Nếu bạn bắt đầu bằng điểm hình học, vùng đệm thực sự là một hình tròn.

Bạn có thể xem bộ đệm thực sự hoạt động gì bằng cách gọi:

SELECT ASTEXT(BUFFER(GEOMFROMTEXT('POINT(5 5)'),3))

(kết quả là khá dài, vì vậy tôi sẽ không đăng nó ở đây) Nó thực sự tạo ra đa giác đại diện cho bộ đệm - trong trường hợp này (và MariaDB của tôi) kết quả là đa giác 126 điểm, gần với một vòng tròn. Với một đa giác như vậy, bạn có thể làm việc như bạn sẽ làm việc với bất kỳ đa giác nào khác. Vì vậy, sẽ không có hình phạt về hiệu suất.

Vì vậy, nếu bạn muốn chọn tất cả các đa giác nằm trong một vòng tròn bạn có thể rửa sạch và lặp lại ví dụ trước (điều này sẽ chỉ tìm thấy hình vuông số 3)

SELECT id,AsText(poly) FROM  `spatial` 
    WHERE 
        ST_Contains(
          Buffer(GEOMFROMTEXT('POINT(6 15)'), 10),
          `poly`
        )
;

Chọn tất cả các đa giác giao với một hình tròn

SELECT id,AsText(poly) FROM  `spatial` 
    WHERE 
        ST_Intersects(
          Buffer(GEOMFROMTEXT('POINT(6 15)'), 10),
          `poly`
        )
;

Khi làm việc với các hình dạng khác với hình chữ nhật, bạn nên sử dụng ST_* chức năng. Các hàm không có ST_ sử dụng một hình chữ nhật có giới hạn. Vì vậy, ví dụ trước chọn hình tam giác số 4 mặc dù nó không nằm trong hình tròn.

Dưới dạng Buffer() tạo ra các đa giác khá lớn, chắc chắn sẽ có một số hình phạt về hiệu suất khi sử dụng ST_Distance() phương pháp. Thật không may, tôi không thể định lượng nó. Bạn sẽ phải thực hiện một số đo điểm chuẩn.

Một cách khác để tìm các đối tượng theo khoảng cách là sử dụng ST_Distance() hàm số.

Chọn tất cả các phần tử từ bảng và tính khoảng cách của chúng từ điểm POINT (6 15)

SELECT id, AsText(`poly`), 
    ST_Distance(poly, GeomFromText('POINT(6 15)')) 
    FROM `spatial`
;

Bạn có thể sử dụng ST_Distance trong WHERE cũng như mệnh đề.

Chọn tất cả các phần tử có khoảng cách từ POINT (0 0) nhỏ hơn hoặc bằng 10 (chọn # 1, # 2 và # 3)

SELECT id, AsText(`poly`), 
    ST_Distance(poly, GeomFromText('POINT(6 15)')) 
    FROM `spatial`
    WHERE ST_Distance(poly, GeomFromText('POINT(6 15)')) <= 10
;

Mặc dù khoảng cách được tính từ điểm gần nhất đến điểm gần nhất. Làm cho nó tương tự như ST_Intersect . Vì vậy, ví dụ trên sẽ chọn # 2 mặc dù nó không hoàn toàn nằm trong vòng kết nối.

Và có, đối số thứ hai (0) cho GeomFromText(text,srid) , không đóng bất kỳ vai trò nào, bạn có thể yên tâm bỏ qua. Tôi đã chọn nó từ một số mẫu và nó bị mắc kẹt trong câu trả lời của tôi. Tôi đã bỏ nó đi trong các lần chỉnh sửa sau này.

btw. phpMyAdmin hỗ trợ cho phần mở rộng không gian không phải là hoàn hảo, nhưng nó giúp một chút để xem những gì có trong cơ sở dữ liệu của bạn. Đã giúp tôi với những hình ảnh mà tôi đã đính kèm.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cột không xác định MySQL trong mệnh đề ON

  2. Neo4j - Tạo chỉ mục bằng Cypher

  3. Mẹo nâng cấp từ MySQL 5.7 lên MySQL 8

  4. Lỗi PHP, MySQL:Số cột không khớp với số giá trị ở hàng 1

  5. Xóa các bản ghi trùng lặp mà không cần tạo bảng tạm thời