<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Help with Feature Layer where query in Python Questions</title>
    <link>https://community.esri.com/t5/python-questions/help-with-feature-layer-where-query/m-p/1588552#M73783</link>
    <description>&lt;P&gt;This is absolutely overkill, but I've been on a class kick lately and have actually been working on a SQLQuery class that can help out with this:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;from __future__ import annotations

class SQLQuery:
    def __init__(self, field: str, comparisons: set=None):
        self.field = field
        if ' ' in field:
            self.field = f'"{field}"' # Wrap spaced field in ""
        self.comparisons = comparisons
        if not comparisons:
            self.comparisons = set() # initialize empty set
    
    def _guard(self, value: str | int | float) -&amp;gt; str | int | float | None:
        """Reject any non standard inputs, add single quotes to strings
        NOTE: This does not sanitize the input! Someone could still inject SQL queries
        into a string value.
        """
        if isinstance(value, str):
            value = f"'{value}'"
        elif not isinstance(value, int | float):
            raise ValueError(f"Invalid Comparison {value}, must be str | int | float")
        if value in self.comparisons:
            value = None
        return value
               
    def __add__(self, value: str | int | float) -&amp;gt; SQLQuery:
        comps = set(self.comparisons)
        comps.add(self._guard(value))
        return SQLQuery(self.field, comps)
    
    def __sub__(self, value: str | int | float) -&amp;gt; SQLQuery:
        comps = set(self.comparisons)
        comps.remove(self._guard(value))
        return SQLQuery(self.field, comps)
    
    def append(self, value: str | int | float) -&amp;gt; None:
        self.comparisons.add(self._guard(value))
    
    def extend(self, comparisons: list) -&amp;gt; None:
        for value in comparisons:
            self.comparisons.add(self._guard(value))
    
    def __repr__(self) -&amp;gt; str:
        return f"SQLQuery({self.field=}, {self.comparisons=})"
    
    def _compare(self, inclusive: bool):
        # No comparison returns all
        if not self.comparisons:
            return "1 = 1"
        
        # Use single op for one comparison
        if len(self.comparisons) == 1:
            return f"{self.field} {'=' if inclusive else '&amp;lt;&amp;gt;'} {list(self.comparisons)[0]}"
        
        # Use IN operator for multiple comparisons
        if len(self.comparisons) &amp;gt; 1:
            return f"{self.field} {'IN' if inclusive else 'NOT IN'} ({','.join(map(str, self.comparisons))})"
        
    @property
    def inclusive(self) -&amp;gt; str:
        return self._compare(inclusive=True)
    
    @property
    def exclusive(self) -&amp;gt; str:
        return self._compare(inclusive=False)&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;It's pretty basic, but it lets you write queries like this:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;&amp;gt;&amp;gt;&amp;gt; query = SQLQuery('inspection_number')
&amp;gt;&amp;gt;&amp;gt; out_fields = ['objectid', 'globalid', 'date_of_inspection', ...]
&amp;gt;&amp;gt;&amp;gt; fs1_features = fs1_layer.query(
...    where=(query + 'Ad-hoc Inspection').exclusive, 
...    out_fields=out_fields, 
...    return_geometry=False).features

&amp;gt;&amp;gt;&amp;gt; query
SQLQuery(field='inspection_number', comparisons=set())

&amp;gt;&amp;gt;&amp;gt; (query + 'Ad-hoc Inspection').exclusive
"inspection_number &amp;lt;&amp;gt; 'Ad-hoc Inspection'"

&amp;gt;&amp;gt;&amp;gt; (query + 'Ad-hoc Inspection' + 'Other').exclusive
"inspection_number NOT IN ('Ad-hoc Inspection','Other')"

&amp;gt;&amp;gt;&amp;gt; (query + 'Ad-hoc Inspection' + 'Other').inclusive
"inspection_number IN ('Ad-hoc Inspection','Other')"

&amp;gt;&amp;gt;&amp;gt; # Joining Queries
&amp;gt;&amp;gt;&amp;gt; query1 = SQLQuery('field')
&amp;gt;&amp;gt;&amp;gt; query2 = SQLQuery('field2')
&amp;gt;&amp;gt;&amp;gt; ' AND '.join(
...     [
...         (query1 + 'val1').inclusive, 
...         (query2 + 'val2').exclusive
...     ]
... )
"field = 'val1' AND field2 &amp;lt;&amp;gt; 'val2'"&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;I hate having to keep track of a ton of hardcoded SQL strings in my projects, so using a little interface like this can sometimes make it easier. Plus the query construction is handled by the inclusive and exclusive properties, so you'll always be sending a query with that format.&lt;/P&gt;</description>
    <pubDate>Mon, 24 Feb 2025 19:47:13 GMT</pubDate>
    <dc:creator>HaydenWelch</dc:creator>
    <dc:date>2025-02-24T19:47:13Z</dc:date>
    <item>
      <title>Help with Feature Layer where query</title>
      <link>https://community.esri.com/t5/python-questions/help-with-feature-layer-where-query/m-p/1588432#M73778</link>
      <description>&lt;P&gt;HI Brains Trust. I'm having some trouble with a feature layer query. I can't seem to find answers anywhere.&amp;nbsp;&lt;/P&gt;&lt;P&gt;Simply put, I have a feature service URL (from ArcGIS Online) and I'm trying to get a list of features filtered to exclude rows with a particular value in the "inspection_number" field.&amp;nbsp;&lt;/P&gt;&lt;P&gt;Below is my code - what am I doing wrong? I keep getting Error Code: 400 - 'where' parameter is invalid&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;fs1_features = fs1_layer.query(where='inspection_number != "Ad-hoc Inspection"', out_fields=['objectid', 'globalid', 'date_of_inspection', 'plantation', 'years_planted', 'username', 'inspection_number'], return_geometry=False).features&lt;/LI-CODE&gt;&lt;P&gt;I've successfully made it work using an objectid value e.g.&amp;nbsp;&amp;nbsp;fs1_features = fs1_layer.query(where='inspection_number &amp;gt; 1000') but can't make it work with a text value.&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Mon, 24 Feb 2025 06:40:20 GMT</pubDate>
      <guid>https://community.esri.com/t5/python-questions/help-with-feature-layer-where-query/m-p/1588432#M73778</guid>
      <dc:creator>LindsayRaabe_FPCWA</dc:creator>
      <dc:date>2025-02-24T06:40:20Z</dc:date>
    </item>
    <item>
      <title>Re: Help with Feature Layer where query</title>
      <link>https://community.esri.com/t5/python-questions/help-with-feature-layer-where-query/m-p/1588462#M73779</link>
      <description>&lt;P&gt;To ensure clarity and consistency, it's better to use the &amp;lt;&amp;gt; operator for "not equal" in SQL, as it is the standard for many SQL dialects. Therefore, the WHERE condition should be written as:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="sql"&gt;WHERE inspection_number &amp;lt;&amp;gt; 'Ad-hoc Inspection'&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;This approach avoids ambiguity and aligns with best practices in SQL queries. Let me know if you need further clarification!&lt;/P&gt;</description>
      <pubDate>Tue, 25 Feb 2025 07:38:52 GMT</pubDate>
      <guid>https://community.esri.com/t5/python-questions/help-with-feature-layer-where-query/m-p/1588462#M73779</guid>
      <dc:creator>nafizpervez</dc:creator>
      <dc:date>2025-02-25T07:38:52Z</dc:date>
    </item>
    <item>
      <title>Re: Help with Feature Layer where query</title>
      <link>https://community.esri.com/t5/python-questions/help-with-feature-layer-where-query/m-p/1588472#M73780</link>
      <description>&lt;P&gt;Hey &lt;a href="https://community.esri.com/t5/user/viewprofilepage/user-id/148829"&gt;@LindsayRaabe_FPCWA&lt;/a&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;In addition to what nafizpervez mentioned, I like to use the &amp;lt;&amp;gt; as well, but I believe the issue comes in where you're using the double quotes instead of single quotes, here's what I would try:&lt;/P&gt;&lt;LI-CODE lang="python"&gt;fs1_features = fs1_layer.query(where="inspection_number &amp;lt;&amp;gt; 'Ad-hoc Inspection'", out_fields=['objectid', 'globalid', 'date_of_inspection', 'plantation', 'years_planted', 'username', 'inspection_number'], return_geometry=False).features&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;SQL is pretty particular about using the single quotes when referencing string values.&lt;/P&gt;&lt;P&gt;Cody&lt;/P&gt;</description>
      <pubDate>Mon, 24 Feb 2025 12:04:51 GMT</pubDate>
      <guid>https://community.esri.com/t5/python-questions/help-with-feature-layer-where-query/m-p/1588472#M73780</guid>
      <dc:creator>CodyPatterson</dc:creator>
      <dc:date>2025-02-24T12:04:51Z</dc:date>
    </item>
    <item>
      <title>Re: Help with Feature Layer where query</title>
      <link>https://community.esri.com/t5/python-questions/help-with-feature-layer-where-query/m-p/1588501#M73782</link>
      <description>&lt;P&gt;This is probably it. SQL reads double quotes as field names and single quotes as strings. (This is one of the ways you can call a field name with a space in it, by encasing it in double quotes, iirc)&lt;/P&gt;</description>
      <pubDate>Mon, 24 Feb 2025 14:01:54 GMT</pubDate>
      <guid>https://community.esri.com/t5/python-questions/help-with-feature-layer-where-query/m-p/1588501#M73782</guid>
      <dc:creator>AlfredBaldenweck</dc:creator>
      <dc:date>2025-02-24T14:01:54Z</dc:date>
    </item>
    <item>
      <title>Re: Help with Feature Layer where query</title>
      <link>https://community.esri.com/t5/python-questions/help-with-feature-layer-where-query/m-p/1588552#M73783</link>
      <description>&lt;P&gt;This is absolutely overkill, but I've been on a class kick lately and have actually been working on a SQLQuery class that can help out with this:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;from __future__ import annotations

class SQLQuery:
    def __init__(self, field: str, comparisons: set=None):
        self.field = field
        if ' ' in field:
            self.field = f'"{field}"' # Wrap spaced field in ""
        self.comparisons = comparisons
        if not comparisons:
            self.comparisons = set() # initialize empty set
    
    def _guard(self, value: str | int | float) -&amp;gt; str | int | float | None:
        """Reject any non standard inputs, add single quotes to strings
        NOTE: This does not sanitize the input! Someone could still inject SQL queries
        into a string value.
        """
        if isinstance(value, str):
            value = f"'{value}'"
        elif not isinstance(value, int | float):
            raise ValueError(f"Invalid Comparison {value}, must be str | int | float")
        if value in self.comparisons:
            value = None
        return value
               
    def __add__(self, value: str | int | float) -&amp;gt; SQLQuery:
        comps = set(self.comparisons)
        comps.add(self._guard(value))
        return SQLQuery(self.field, comps)
    
    def __sub__(self, value: str | int | float) -&amp;gt; SQLQuery:
        comps = set(self.comparisons)
        comps.remove(self._guard(value))
        return SQLQuery(self.field, comps)
    
    def append(self, value: str | int | float) -&amp;gt; None:
        self.comparisons.add(self._guard(value))
    
    def extend(self, comparisons: list) -&amp;gt; None:
        for value in comparisons:
            self.comparisons.add(self._guard(value))
    
    def __repr__(self) -&amp;gt; str:
        return f"SQLQuery({self.field=}, {self.comparisons=})"
    
    def _compare(self, inclusive: bool):
        # No comparison returns all
        if not self.comparisons:
            return "1 = 1"
        
        # Use single op for one comparison
        if len(self.comparisons) == 1:
            return f"{self.field} {'=' if inclusive else '&amp;lt;&amp;gt;'} {list(self.comparisons)[0]}"
        
        # Use IN operator for multiple comparisons
        if len(self.comparisons) &amp;gt; 1:
            return f"{self.field} {'IN' if inclusive else 'NOT IN'} ({','.join(map(str, self.comparisons))})"
        
    @property
    def inclusive(self) -&amp;gt; str:
        return self._compare(inclusive=True)
    
    @property
    def exclusive(self) -&amp;gt; str:
        return self._compare(inclusive=False)&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;It's pretty basic, but it lets you write queries like this:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;&amp;gt;&amp;gt;&amp;gt; query = SQLQuery('inspection_number')
&amp;gt;&amp;gt;&amp;gt; out_fields = ['objectid', 'globalid', 'date_of_inspection', ...]
&amp;gt;&amp;gt;&amp;gt; fs1_features = fs1_layer.query(
...    where=(query + 'Ad-hoc Inspection').exclusive, 
...    out_fields=out_fields, 
...    return_geometry=False).features

&amp;gt;&amp;gt;&amp;gt; query
SQLQuery(field='inspection_number', comparisons=set())

&amp;gt;&amp;gt;&amp;gt; (query + 'Ad-hoc Inspection').exclusive
"inspection_number &amp;lt;&amp;gt; 'Ad-hoc Inspection'"

&amp;gt;&amp;gt;&amp;gt; (query + 'Ad-hoc Inspection' + 'Other').exclusive
"inspection_number NOT IN ('Ad-hoc Inspection','Other')"

&amp;gt;&amp;gt;&amp;gt; (query + 'Ad-hoc Inspection' + 'Other').inclusive
"inspection_number IN ('Ad-hoc Inspection','Other')"

&amp;gt;&amp;gt;&amp;gt; # Joining Queries
&amp;gt;&amp;gt;&amp;gt; query1 = SQLQuery('field')
&amp;gt;&amp;gt;&amp;gt; query2 = SQLQuery('field2')
&amp;gt;&amp;gt;&amp;gt; ' AND '.join(
...     [
...         (query1 + 'val1').inclusive, 
...         (query2 + 'val2').exclusive
...     ]
... )
"field = 'val1' AND field2 &amp;lt;&amp;gt; 'val2'"&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;I hate having to keep track of a ton of hardcoded SQL strings in my projects, so using a little interface like this can sometimes make it easier. Plus the query construction is handled by the inclusive and exclusive properties, so you'll always be sending a query with that format.&lt;/P&gt;</description>
      <pubDate>Mon, 24 Feb 2025 19:47:13 GMT</pubDate>
      <guid>https://community.esri.com/t5/python-questions/help-with-feature-layer-where-query/m-p/1588552#M73783</guid>
      <dc:creator>HaydenWelch</dc:creator>
      <dc:date>2025-02-24T19:47:13Z</dc:date>
    </item>
    <item>
      <title>Re: Help with Feature Layer where query</title>
      <link>https://community.esri.com/t5/python-questions/help-with-feature-layer-where-query/m-p/1588807#M73786</link>
      <description>&lt;P&gt;I swear I tried this and every other combination of single and double commas possible, yet it continuously failed. Copy and pasted your code straight over mine and it worked first time. 🤦&lt;/P&gt;&lt;P&gt;Thanks for helping! Now to move on to the next issue!&lt;/P&gt;</description>
      <pubDate>Tue, 25 Feb 2025 01:02:32 GMT</pubDate>
      <guid>https://community.esri.com/t5/python-questions/help-with-feature-layer-where-query/m-p/1588807#M73786</guid>
      <dc:creator>LindsayRaabe_FPCWA</dc:creator>
      <dc:date>2025-02-25T01:02:32Z</dc:date>
    </item>
    <item>
      <title>Re: Help with Feature Layer where query</title>
      <link>https://community.esri.com/t5/python-questions/help-with-feature-layer-where-query/m-p/1588815#M73787</link>
      <description>&lt;P&gt;Yeah - this is next level and I'm definitely not requiring something that functional. Thanks for sharing though. Somone else may find it suitable for their project!&lt;/P&gt;</description>
      <pubDate>Tue, 25 Feb 2025 01:43:53 GMT</pubDate>
      <guid>https://community.esri.com/t5/python-questions/help-with-feature-layer-where-query/m-p/1588815#M73787</guid>
      <dc:creator>LindsayRaabe_FPCWA</dc:creator>
      <dc:date>2025-02-25T01:43:53Z</dc:date>
    </item>
    <item>
      <title>Re: Help with Feature Layer where query</title>
      <link>https://community.esri.com/t5/python-questions/help-with-feature-layer-where-query/m-p/1588816#M73788</link>
      <description>&lt;P&gt;Thanks - I suspect it ended up being both the &amp;lt;&amp;gt; and the incorrect "" '' usage as discussed below.&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 25 Feb 2025 01:45:04 GMT</pubDate>
      <guid>https://community.esri.com/t5/python-questions/help-with-feature-layer-where-query/m-p/1588816#M73788</guid>
      <dc:creator>LindsayRaabe_FPCWA</dc:creator>
      <dc:date>2025-02-25T01:45:04Z</dc:date>
    </item>
    <item>
      <title>Re: Help with Feature Layer where query</title>
      <link>https://community.esri.com/t5/python-questions/help-with-feature-layer-where-query/m-p/1588836#M73789</link>
      <description>&lt;P&gt;Oh course! I'm just trying to get as much code onto this platform as possible honestly. There's a general lack of extensive solutions and I'm hoping that answers like this will help guide the next generation of people trying to write GIS code.&lt;/P&gt;</description>
      <pubDate>Tue, 25 Feb 2025 04:13:04 GMT</pubDate>
      <guid>https://community.esri.com/t5/python-questions/help-with-feature-layer-where-query/m-p/1588836#M73789</guid>
      <dc:creator>HaydenWelch</dc:creator>
      <dc:date>2025-02-25T04:13:04Z</dc:date>
    </item>
  </channel>
</rss>

