<p dir="auto"><strong>Migrated issue, originally created by Michael Bayer (<a href="https://github.com/zzzeek">@zzzeek</a>)</strong></p>
<p dir="auto">right now session.__binds uses mappers completely.  This makes it impossible to feed in abstract classes and also because it links to base_mapper it's not possible to change the bind along a class hierarchy either (like a concrete hierarchy).</p>
<p dir="auto">propose that __binds stores classes directly, and this can likely be a fallback in addition to what we have now.  this is kind of a proof of concept</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py
index 89d9946..f63adfb 100644
--- a/lib/sqlalchemy/orm/session.py
+++ b/lib/sqlalchemy/orm/session.py
@@ -636,13 +636,20 @@ class Session(_SessionClassMethods):

         if binds is not None:
             for mapperortable, bind in binds.items():
-                insp = inspect(mapperortable)
-                if insp.is_selectable:
-                    self.bind_table(mapperortable, bind)
-                elif insp.is_mapper:
-                    self.bind_mapper(mapperortable, bind)
+                try:
+                    insp = inspect(mapperortable)
+                except exc.NoInspectionAvailable:
+                    if isinstance(mapperortable, type):
+                        self.bind_cls(mapperortable, bind)
+                    else:
+                        raise exc.ArgumentError(&quot;Not acceptable bind target: %s&quot; % mapperortable)
                 else:
-                    assert False
+                    if insp.is_selectable:
+                        self.bind_table(mapperortable, bind)
+                    elif insp.is_mapper:
+                        self.bind_mapper(mapperortable, bind)
+                    else:
+                        assert False


         if not self.autocommit:
@@ -1039,6 +1046,17 @@ class Session(_SessionClassMethods):
         for t in mapper._all_tables:
             self.__binds[t] = bind

+    def bind_class(self, cls, bind):
+        &quot;&quot;&quot;Bind operations for an unmapped class to a Connectable.
+
+        The behavior here is that a subclass of cls which is mapped
+        will be linked to this bind.
+
+        .. versionadded:: 1.0
+
+        &quot;&quot;&quot;
+        self.__binds[cls] = bind
+
     def bind_table(self, table, bind):
         &quot;&quot;&quot;Bind operations on a Table to a Connectable.

@@ -1124,6 +1142,12 @@ class Session(_SessionClassMethods):
                     return self.__binds[c_mapper.base_mapper]
                 elif c_mapper.mapped_table in self.__binds:
                     return self.__binds[c_mapper.mapped_table]
+                else:
+                    for cls in c_mapper.class_.__mro__:
+                        if cls in self.__binds:
+                            bind = self.__binds[cls]
+                            self.bind_mapper(c_mapper, bind)
+                            return bind
             if clause is not None:
                 for t in sql_util.find_tables(clause, include_crud=True):
                     if t in self.__binds:
"><pre class="notranslate"><code class="notranslate">diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py
index 89d9946..f63adfb 100644
--- a/lib/sqlalchemy/orm/session.py
+++ b/lib/sqlalchemy/orm/session.py
@@ -636,13 +636,20 @@ class Session(_SessionClassMethods):

         if binds is not None:
             for mapperortable, bind in binds.items():
-                insp = inspect(mapperortable)
-                if insp.is_selectable:
-                    self.bind_table(mapperortable, bind)
-                elif insp.is_mapper:
-                    self.bind_mapper(mapperortable, bind)
+                try:
+                    insp = inspect(mapperortable)
+                except exc.NoInspectionAvailable:
+                    if isinstance(mapperortable, type):
+                        self.bind_cls(mapperortable, bind)
+                    else:
+                        raise exc.ArgumentError("Not acceptable bind target: %s" % mapperortable)
                 else:
-                    assert False
+                    if insp.is_selectable:
+                        self.bind_table(mapperortable, bind)
+                    elif insp.is_mapper:
+                        self.bind_mapper(mapperortable, bind)
+                    else:
+                        assert False


         if not self.autocommit:
@@ -1039,6 +1046,17 @@ class Session(_SessionClassMethods):
         for t in mapper._all_tables:
             self.__binds[t] = bind

+    def bind_class(self, cls, bind):
+        """Bind operations for an unmapped class to a Connectable.
+
+        The behavior here is that a subclass of cls which is mapped
+        will be linked to this bind.
+
+        .. versionadded:: 1.0
+
+        """
+        self.__binds[cls] = bind
+
     def bind_table(self, table, bind):
         """Bind operations on a Table to a Connectable.

@@ -1124,6 +1142,12 @@ class Session(_SessionClassMethods):
                     return self.__binds[c_mapper.base_mapper]
                 elif c_mapper.mapped_table in self.__binds:
                     return self.__binds[c_mapper.mapped_table]
+                else:
+                    for cls in c_mapper.class_.__mro__:
+                        if cls in self.__binds:
+                            bind = self.__binds[cls]
+                            self.bind_mapper(c_mapper, bind)
+                            return bind
             if clause is not None:
                 for t in sql_util.find_tables(clause, include_crud=True):
                     if t in self.__binds:

</code></pre></div>
<p dir="auto">the tests here also need a rework, with an emphasis on straight unit testing of get_bind().  test_session -&gt; BindTest is really just integration tests.</p>
<h3 dir="auto">Describe the bug</h3>
<p dir="auto">I am passing a very simple SQL query to a server via Python's SQLAlchemy library. Here is my code:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="def query4():
        ed_notes = sa.Table(&quot;ED_NOTES_MASTER&quot;,metadata,autoload=True,autoload_with=engine)
        note_query = sa.select([ed_notes.columns[&quot;PT_FIN&quot;],
            ed_notes.columns[&quot;RESULT_TITLE_TEXT&quot;],
            ed_notes.columns[&quot;RESULT&quot;],
            ed_notes.columns[&quot;RESULT_DT_TM&quot;]]).where(ed_notes.columns[&quot;PT_FIN&quot;].in_(unique_fins)).where(start_time&lt;ed_notes.columns[&quot;RESULT_DT_TM&quot;]).where(end_time&gt;ed_notes.columns[&quot;RESULT_DT_TM&quot;])
        result = connection.execute(note_query)
        resultset = result.all()
        note_data_prelim = pd.DataFrame(resultset)
        return note_data_prelim"><pre class="notranslate"><code class="notranslate">def query4():
        ed_notes = sa.Table("ED_NOTES_MASTER",metadata,autoload=True,autoload_with=engine)
        note_query = sa.select([ed_notes.columns["PT_FIN"],
            ed_notes.columns["RESULT_TITLE_TEXT"],
            ed_notes.columns["RESULT"],
            ed_notes.columns["RESULT_DT_TM"]]).where(ed_notes.columns["PT_FIN"].in_(unique_fins)).where(start_time&lt;ed_notes.columns["RESULT_DT_TM"]).where(end_time&gt;ed_notes.columns["RESULT_DT_TM"])
        result = connection.execute(note_query)
        resultset = result.all()
        note_data_prelim = pd.DataFrame(resultset)
        return note_data_prelim
</code></pre></div>
<p dir="auto">the variable "unique_fins" is a list of over 50,000 unique identifiers that I am trying to specifically query. When this query is run, the following error results:</p>
<p dir="auto"><code class="notranslate"> sqlalchemy.exc.ProgrammingError: (pyodbc.ProgrammingError) ('The SQL contains -11872 parameter markers, but 53664 parameters were supplied', 'HY000')</code></p>
<p dir="auto">Any ideas on what is going on? The problem is definitely arising in the ed_notes.columns["PT_FIN"].in_(unique_fins) portion of the query.</p>
<p dir="auto">Thanks in advance!</p>
<h3 dir="auto">To Reproduce</h3>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="unique_fins = low_triage_only[&quot;PT_FIN&quot;].unique().tolist()

    def query4():
        ed_notes = sa.Table(&quot;ED_NOTES_MASTER&quot;,metadata,autoload=True,autoload_with=engine)
        note_query = sa.select([ed_notes.columns[&quot;PT_FIN&quot;],
            ed_notes.columns[&quot;RESULT_TITLE_TEXT&quot;],
            ed_notes.columns[&quot;RESULT&quot;],
            ed_notes.columns[&quot;RESULT_DT_TM&quot;]]).where(ed_notes.columns[&quot;PT_FIN&quot;].in_(unique_fins)).where(start_time&lt;ed_notes.columns[&quot;RESULT_DT_TM&quot;]).where(end_time&gt;ed_notes.columns[&quot;RESULT_DT_TM&quot;])
        result = connection.execute(note_query)
        resultset = result.fetchall()
        return resultset"><pre class="notranslate"><span class="pl-s1">unique_fins</span> <span class="pl-c1">=</span> <span class="pl-s1">low_triage_only</span>[<span class="pl-s">"PT_FIN"</span>].<span class="pl-en">unique</span>().<span class="pl-en">tolist</span>()

    <span class="pl-k">def</span> <span class="pl-en">query4</span>():
        <span class="pl-s1">ed_notes</span> <span class="pl-c1">=</span> <span class="pl-s1">sa</span>.<span class="pl-v">Table</span>(<span class="pl-s">"ED_NOTES_MASTER"</span>,<span class="pl-s1">metadata</span>,<span class="pl-s1">autoload</span><span class="pl-c1">=</span><span class="pl-c1">True</span>,<span class="pl-s1">autoload_with</span><span class="pl-c1">=</span><span class="pl-s1">engine</span>)
        <span class="pl-s1">note_query</span> <span class="pl-c1">=</span> <span class="pl-s1">sa</span>.<span class="pl-en">select</span>([<span class="pl-s1">ed_notes</span>.<span class="pl-s1">columns</span>[<span class="pl-s">"PT_FIN"</span>],
            <span class="pl-s1">ed_notes</span>.<span class="pl-s1">columns</span>[<span class="pl-s">"RESULT_TITLE_TEXT"</span>],
            <span class="pl-s1">ed_notes</span>.<span class="pl-s1">columns</span>[<span class="pl-s">"RESULT"</span>],
            <span class="pl-s1">ed_notes</span>.<span class="pl-s1">columns</span>[<span class="pl-s">"RESULT_DT_TM"</span>]]).<span class="pl-en">where</span>(<span class="pl-s1">ed_notes</span>.<span class="pl-s1">columns</span>[<span class="pl-s">"PT_FIN"</span>].<span class="pl-en">in_</span>(<span class="pl-s1">unique_fins</span>)).<span class="pl-en">where</span>(<span class="pl-s1">start_time</span><span class="pl-c1">&lt;</span><span class="pl-s1">ed_notes</span>.<span class="pl-s1">columns</span>[<span class="pl-s">"RESULT_DT_TM"</span>]).<span class="pl-en">where</span>(<span class="pl-s1">end_time</span><span class="pl-c1">&gt;</span><span class="pl-s1">ed_notes</span>.<span class="pl-s1">columns</span>[<span class="pl-s">"RESULT_DT_TM"</span>])
        <span class="pl-s1">result</span> <span class="pl-c1">=</span> <span class="pl-s1">connection</span>.<span class="pl-en">execute</span>(<span class="pl-s1">note_query</span>)
        <span class="pl-s1">resultset</span> <span class="pl-c1">=</span> <span class="pl-s1">result</span>.<span class="pl-en">fetchall</span>()
        <span class="pl-k">return</span> <span class="pl-s1">resultset</span></pre></div>
<h3 dir="auto">Error</h3>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="sqlalchemy.exc.ProgrammingError: (pyodbc.ProgrammingError) ('The SQL contains -11877 parameter markers, but 53659 parameters were supplied', 'HY000')"><pre class="notranslate"><code class="notranslate">sqlalchemy.exc.ProgrammingError: (pyodbc.ProgrammingError) ('The SQL contains -11877 parameter markers, but 53659 parameters were supplied', 'HY000')
</code></pre></div>
<h3 dir="auto">Versions</h3>
<ul dir="auto">
<li>OS: Windows 10</li>
<li>Python: 3.8.12</li>
<li>SQLAlchemy: 1.4.27</li>
<li>Database: Microsoft SQL Server</li>
<li>DBAPI (eg: psycopg, cx_oracle, mysqlclient): Microsoft ODBC 17 Driver</li>
</ul>
<h3 dir="auto">Additional context</h3>
<p dir="auto"><em>No response</em></p>