3

I created a virtual layer which contains all the geometries and attributes from a shapefile using the following code:

vlayer = QgsVectorLayer( "?layer=ogr:path/to/shapefile", "layerName", "virtual" )
QgsMapLayerRegistry.instance().addMapLayer(vlayer)

But now I want to update the SQL query for this virtual layer. Is this possible using PyQGIS?


Example:

How could I update the virtual layer with the following simple query:

SELECT * FROM anotherLayer WHERE ID < 10
  • Are you wanting a subset of the virtual layer? – artwork21 Nov 17 '16 at 13:25
  • @artwork21 - No, not a subset. My idea (for a plugin) was to have a single virtual layer which 'duplicates' another layer in terms of geometry and attributes. So if I have two layers ("layer1" and "layer2") and one virtual layer, if the user selects "layer1" from the plugin, the virtual layer will be updated to be exactly like "layer1". And vice-versa if the user selects "layer2". – Joseph Nov 17 '16 at 13:52
3

It should be enough to update the layer data source with an appropriate URI. See the following examples involving 2 layers from Natural Earth (airports and countries) and 2 different queries for each layer.

pathAirports = u'/docs/geodata/world/ne_10m_airports.shp'
pathCountries = u'/docs/geodata/world/ne_10m_admin_0_countries.shp' 

queryAirports="SELECT * FROM airports"
queryAirports2="SELECT * FROM airports WHERE type='major'"
queryCountries="SELECT * FROM countries"
queryCountries2="SELECT * FROM countries WHERE SUBREGION='South America'"

layer = QgsVectorLayer(
            "?layer=ogr:{}:airports&query={}".format( pathAirports, queryAirports ),
            "Airports",
            "virtual" )
QgsMapLayerRegistry.instance().addMapLayer( layer )

layer.setDataSource(
            "?layer=ogr:{}:airports&query={}".format( pathAirports, queryAirports2 ),
            "Some Airports", 
            "virtual" )

layer.setDataSource(
            "?layer=ogr:{}:countries&query={}".format( pathCountries, queryCountries ),
            "Countries", 
            "virtual" )

layer.setDataSource(
            "?layer=ogr:{}:countries&query={}".format( pathCountries, queryCountries2 ), 
            "Some countries", 
            "virtual" )

However, there seems to be a bug with Virtual Layers that doesn't allow you to select features properly using canvas tools. For instance, after running the last line above, I cannot select Brasil using the select tool (it keeps selecting Argentina!). I've confirmed this on QGIS v2.14.8 (GNU/Linux), QGIS 2.16.3 (Windows 7), and a recent QGIS build v2.99 (GNU/Linux). This is not a bug due to the PyQGIS code above, in fact, creating the virtual layer from QGIS GUI (either from DB Manager or Manage Layers Toolbar) I get the same result. Can you confirm such behavior?

  • Many thanks for your answer, I will test this later today and report back =) – Joseph Nov 21 '16 at 10:38
  • Up until loading the virtual layer works fine. But when I change the URI using the first setDataSource(), the attribtute table is empty. When changing to the last two setDataSource(), I receive the following error: Query preparation error on SELECT Count(*), Min(MbrMinX(""),Min(MbrMinY(""), Max(MbrMaxX(""), Max(MbrMaxY("") FROM : near " ": syntax error – Joseph Nov 21 '16 at 13:43
  • And you're using QGIS v...? Have you reproduce that error using NE dataset? – Germán Carrillo Nov 21 '16 at 13:52
  • 1
    Yeap, doesn't seem to be an option yet. Strangely, I hadn't notice that problem using Virtual Layers before from the QGIS GUI. I'll check later if there is already a reported issue about it or I'll create it. – Germán Carrillo Nov 21 '16 at 14:21
  • 1
    Great! It's a very powerful QGIS feature, it would be a pity to discard it by that bug. – Germán Carrillo Nov 22 '16 at 12:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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