0

I have several map layers in a SpatiaLite database in memory. All of these have been copied from multiple separate on-disk databases. I want to do a query that involves updating the columns in a layer with points (point_layer) with entries from the columns of the same name in other layers where the points intersect with those layers. In my example this other layer is polygon_layer which has also been copied to the in-memory database.

I have one working query:

QUERY 1

UPDATE point_layer SET field_name = 
   (SELECT field_name FROM polygon_layer 
      WHERE INTERSECTS(polygon_layer.GEOMETRY, point_layer.GEOMETRY))

Which shows me that the geometry works correctly, but it is quite slow and so I would like to speed it up using spatialindex, for which I think the query should be:

QUERY 2

UPDATE point_layer SET field_name = 
   (SELECT lyr.field_name FROM polygon_layer AS lyr 
      WHERE (lyr.ROWID IN
         (SELECT ROWID FROM SpatialIndex 
             WHERE(f_table_name = polygon_layer AND search_frame = point_layer.GEOMETRY)))
      AND
         (INTERSECTS(lyr.GEOMETRY, point_layer.GEOMETRY)))

But while it does not throw up any errors, it does not fill the columns either. This leads me to suspect that there is something wrong with my spatial index. I copied the SpatialIndex tables, as well as the other SpatiaLite reference tables, such as geometry_columns etc, from the original file using create table:

CREATE TABLE "SpatialIndex" AS SELECT * FROM point_copy.SpatialIndex
CREATE TABLE "geometry_columns" AS SELECT * FROM point_copy.SpatialIndex

where point_copy is the attached on-disk spatialite database that contains point_layer. Then I attach the database containing the polygon layer and copy the main table, and INSERT INTO tables such as geometry_columns.

If I do only this, QUERY 2 throws an error at me, namely that it cannot find the SpatialIndex table. So I create new spatial indices:

SELECT CreateSpatialIndex(point_layer, GEOMETRY)
SELECT CreateSpatialIndex(polygon_layer, GEOMETRY)

Which complete without error. QUERY 2 now produces no errors, but also doesn't fill the columns. I have also tried emptying the SpatialIndex table (DELETE FROM SpatialIndex) before creating the new spatial indices, which produces the same results. Should I be copying or creating the spatial indices in some other way, or does QUERY 2 have some kind of problem?

This is using SpatiaLite 4.3.0 through the spatialite plugin for Python3.7. I've excluded the Python bits for convenience, which consists only of cursor executes and connection commits.

2
  • Syntax f_table_name = polygon_layer means "where f_table_name equals to value in a field named polygon_layer". Try f_table_name = 'polygon_layer' instead because you want to search for a certain string.
    – user30184
    Commented Nov 5, 2021 at 12:16
  • I have put all my column and database names in quotes, sadly that didn't work. I believe it should give a "table not found" error if it doesn't recognize it, which I am not getting. Commented Nov 5, 2021 at 15:38

2 Answers 2

1

I have found a solution. As user30184 mentioned the SpatialIndex is a virtual table, and using CREATE TABLE [..] AS SELECT * FROM[...] therefore does not work.

The correct way to create a new spatial index table is:

CREATE VIRTUAL TABLE 'SpatialIndex' USING VirtualSpatialIndex

In which VirtualSpatialIndex is the module from Spatialite that builds the spatial index.

Which can then be populated using:

SELECT CreateSpatialIndex('layer_name', geometry_column)

This is functionally the same as copying the SpatialIndex table. The documentation on building a virtual table (in SQLite) can be found here.

0

The SpatiaLite document https://www.gaia-gis.it/fossil/libspatialite/wiki?name=SpatialIndex has a section about how to use spatial index with an attached database. Your trial looks very odd and would not work with any SpatiaLite database but maybe it is just because some copy-paste errors when you have edited your question.

(SELECT ROWID FROM SpatialIndex WHERE(f_table_name = lyr.field_name...

f_table_name naturally refers to table name and with a normal database you would use

f_table_name='polygon_layer'

but with attached database you must use a prefix

f_table_name='DB=a.polygon_layer'

However, it is not clear for me if your "polygon_layer" is the attached database "a.polygon_layer" or if you have also made a copy of that with something like create table polygon_layer as select * from a.polygon_layer

3
  • I edited my question to clarify that I do indeed copy polygon_layer from an attached database before working with it. I indeed made copying error which is now also fixed. Sadly this was not the problem, as the columns are still not filling with results. Commented Nov 5, 2021 at 11:41
  • I am copying to memory to speed up the update query. Would simply attaching the database be equally fast? Commented Nov 5, 2021 at 11:45
  • Attach database creates only a logical link to the original database file so it would be slower. SpatialIndex is a virtual table and I am not surprised that the CREATE TABLE SpatialIndex as... method fails. But I do not understand why the spatial index created with CreateSpatialIndex would fail. I will do some experiments.
    – user30184
    Commented Nov 5, 2021 at 12:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.