ThinkGeo.com    |     Documentation    |     Premium Support

How to SQL Query an InMemoryFeature Layer?

Hi,


When SQL query a ShapeFileFeatureLayer, the shape file name is used in the query string, for example:


 


 


worldLayer As New ShapeFileFeatureLayer("..\..\SampleData\Data\USStates.shp") dataTable As DataTable = worldLayer.QueryTools.ExecuteQuery("Select * from USStates 

Where PERIMETER > 30 Order by PERIMETER")


How to do a SQL query on an InMemoryFeature layer?


My InMemoryFeature contains some of the features from a postgre Sql layer, but added two more columns. I need to do a sql query on the InMemoryFeature layer something like this: select * where columnname=somevalue


Thanks


Rose


 


 


Dim


 


Dim



It seems it is impossible to do a sql query on InMemoryFeature Layer, as the inMemoryFeatureSource.QueryTools.CanExecuteSqlQuery=false


But I need to get a breakdown analysis based on the column values, do I have to loop through the features one by one? Any better ways to do this?


Thanks


Rose


 



Rose, 
  
 You can create your own InMemoryFeatureSource by inheriting class FeatureSource, overwrite CanExecuteSqlQueryCore to true, use DataSet/DataTable as the internal objects to store the tabular data and overwrite the ExecuteQueryCore method calling the internal DataSet/DataTable using SQL query. In this way, you can have your own InMemoryFeatureSource supporting SQL query. 
  
 I also see there are some requirements only want the tabular data instead of the shape data. We will discuss it to see if we can provide some easier way to do this.  
  
 Thanks, 
  
 Ben

Ben:


I don't think I am the only one who needs to do  both sql query and spatial query on the InMemoryFeature layer. I came from MapInfo background, once you create a sql query, it generates a temp layer, you can further sql query the temp layer. If you want to change the structure of the temp layer but not the original table, you can save a local copy then open it to do whatever modification you want.


Hope MapSuite can provide some easy ways to do any queries on the InMemoryFeature layer.


Thanks


Rose



Posted By Ben on 05-12-2009 04:31 AM 

Rose, 



You can create your own InMemoryFeatureSource by inheriting class FeatureSource, overwrite CanExecuteSqlQueryCore to true, use DataSet/DataTable as the internal objects to store the tabular data and overwrite the ExecuteQueryCore method calling the internal DataSet/DataTable using SQL query. In this way, you can have your own InMemoryFeatureSource supporting SQL query. 



I also see there are some requirements only want the tabular data instead of the shape data. We will discuss it to see if we can provide some easier way to do this. 



Thanks, 



Ben 



Ben,

 


Thanks.


How to build the internal DataTable? I tried, it does not include the new added columns. Any code sample?


Thanks


Rose



Rose, 
  
 I thought if I keep all the data to a DataTable/DataSet, I could query it with SQL. But after hours of investigation, I didn’t find a way to do it. DataTable has a Select() method which can do some simple filter, but cannot support a real complete SQL. There are some parsers but I’m not sure if it works for all SQLs and I don’t think that’s what you want. So I’m afraid we cannot consume SQL for an inMemoryFeatureSource, very sorry to send the last message without enough investigation. 
  
 One possible workaround is to create a tmp Shape File from the inMemoryFeatureLayer, and do the Spatial Query / Sql Query, or whatever modifications you want on that shapeFileFeatureLayer. This seems a bit stupid but it will work. Or we can loop through the features one by one, which is straightforward but cannot accept SQL.  
  
 Sorry for not being so helpful on this. Please let me know if you have any ideas about this. 
  
 Thanks, 
  
 Ben 


Ben:


DataTable has a Select() method, it accepts a simple query string, but it should be enough for me for now. It is much better than a tmp Shape file, as you know the column names must be <=10 chars in Shape file, my data are from Postgre database, most of them have a long but meaningful names, I have to loop through each feature and each column to make the Shape file. I don't think it is a better approach.


I think your idea to create a custom InMemoryFeatureSource and use DataTable to store the internal data,  I loaded the DataTable, but all the columns are of type string, hard to query the data, some of them are supposed to be Double or Integers. Can you show me the sample code to load the data into a DataTable? This will be very helpful!


 


Thanks


Rose



Rose, 
  
 Here is the sample code, hope it helps 
  
 
            DataTable dataTable = new DataTable();
            dataTable.Columns.Add(“Name”);

            Type typeInt32 = Type.GetType(“System.Int32”);
            dataTable.Columns.Add(“Id”, typeInt32);

            Type typeDouble = Type.GetType(“System.Double”);
            dataTable.Columns.Add(“Area”, typeDouble);

            // Add Row 1
            DataRow dataRow1 = dataTable.NewRow();
            dataRow1[“Name”] = “USA”;
            dataRow1[“Id”] = 10;
            dataRow1[“Area”] = 1234.5678;
            dataTable.Rows.Add(dataRow1);

            // Add Row 2
            DataRow dataRow2 = dataTable.NewRow();
            dataRow2[“Name”] = “Mexico”;
            dataRow2[“Id”] = 20;
            dataRow2[“Area”] = 234.567;
            dataTable.Rows.Add(dataRow2);

            DataRow[] dataRow01 = dataTable.Select(“Name = ‘USA’”); // Return USA
            DataRow[] dataRow02 = dataTable.Select(“Id > 10”);      // Return Mexico
            DataRow[] dataRow03 = dataTable.Select(“Id < 50”);      // Return USA and Mexico
            DataRow[] dataRow04 = dataTable.Select(“Area < 1000”);  // Return Mexico
 
  
 Thanks, 
  
 Ben

Ben:


Thanks for your code.


Does that mean I have to hard code the column name and type? That is not practical.


I used the MapEngine.LoadDataTable(features,columnNames) method to load the DataTable, retrieved the column names on the fly, the only problem is all the columns are String type.


Rose



Rose, 
  
 You cannot directly use that method, but you can simply create your own. Here is a sample how to do it. 
  
 
// The new LoadDataTable method
 public DataTable LoadDataTable(IEnumerable<FeatureSourceColumn> featureSourceColumns, IEnumerable<Feature> features)
        {
            DataTable dataTable = new DataTable();
            // Add columns to the dataTable
            foreach (FeatureSourceColumn featureSourceColumn in featureSourceColumns)
            {
                Type type = Type.GetType(featureSourceColumn.TypeName);
                dataTable.Columns.Add(featureSourceColumn.ColumnName, type);
            }

            // Add Rows to the dataTable
            foreach (Feature feature in features)
            {
                DataRow dataRow = dataTable.NewRow();
                foreach (DataColumn dataColumn in dataTable.Columns)
                {
                    dataRow[dataColumn.ColumnName] = feature.ColumnValues[dataColumn.ColumnName];
                }
                dataTable.Rows.Add(dataRow);
            }
            return dataTable;
        }

// Here is my test code.
            FeatureSourceColumn column1 = new FeatureSourceColumn("Name", "System.String", 20);
            FeatureSourceColumn column2 = new FeatureSourceColumn("Age", "System.Int32", 10);
            FeatureSourceColumn[] columns = new FeatureSourceColumn[] { column1, column2 };

            Feature feature1 = new Feature(0, 0);
            feature1.ColumnValues.Add("Name", "Ben");
            feature1.ColumnValues.Add("Age", "2");

            Feature feature2 = new Feature(1, 1);
            feature2.ColumnValues.Add("Name", "Howard");
            feature2.ColumnValues.Add("Age", "1");
            Feature[] features = new Feature[]{feature1, feature2};

            DataTable dataTable = LoadDataTable(columns, features);

 
  
 Thanks, 
  
 Ben