-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
how to work around SQL server disallowing SQL expressions and even label references inside of group_by #4540
Comments
OK, unfortunately, I was assuming SQL server would accept this query, since this is what we can do:
but it doesn't. The ORDER BY can be rendered as above like this:
But we still break out the modified_part_number for GROUP BY, because SQL Server doesn't accept the label name there.
so you answer is in mkleehammer/pyodbc#479, use a subquery:
that's what SQL Server requires so that's what you have to do. Sorry! |
I see, I was hoping that at some point in the stack, the parameters could be named or arranged to mitigate this. But I've gotten some education on how pyodbc works through this: a) ODBC doesn't do named parameters, and b) the way pyodbc processes the query is indeed very direct. The SQL gets passed more or less directly to the ODBC layer as the prepared statement, so there is no place to name the params to the prepared statement. Which is unfortunate, though all of this would be solved if SQL Server supported labels in group by... Technically, the only way around it in pyodbc that I see is to use fully rendered SQL statements instead of parameterized versions, since pyodbc doesn't prepare those. But that would take out some primary means of preventing SQL injection, so it's a non-starter. |
is the issue here the use of parameters? the error message suggests it's the structure of the statement and where the columns are placed. |
It is the parameters, because if SQLAlchemy fully rendered the query and sent it into pyodbc as a string with no parameters (since pyodbc only prepares statements it receives with parameters), it would be something like: select
'05' + right(widgets.part_number, 5) as modified_part_number,
count(id) as part_count
from widgets
group by '05' + right(widgets.part_number, 5)
order by '05' + right(widgets.part_number, 5) Which works with SQL Server, because the '05' remains a literal in the statement and is not being interpolated from various copies in the parameters list. But, I did think of an alternative workaround that yields the same result and appears to work: |
anyway this is how pyodbc / ODBC works, I'd use the subquery approach since it is not safe to use literal parameters in a statement as well as that prepared statements are cacheable. feel free to reopen if you have more questions. |
Using pyodbc for MS SQL Server connections generally works. However, I have found a case where the way SQLAlchemy passes the query to pyodbc breaks for some
group_by
usage.pyodbc operates by taking the sql statement and any parameters, and constructs a prepared statement with those parameters. Any literals in the query, including in
group_by
, are taken as individual parameters, so the same literal given in theselect
andgroup_by
sections of a query become separate parameters. SQL Server's group by validation is very strict, and in this case, it sees those parameters as different, and fails the query.This issue was raised directly on pyodbc last year and closed: mkleehammer/pyodbc#479
Sample setup and query:
The above query yields the following exception:
pyodbc ends up with a query that looks like this, which fails. Note that P1 and P2 are in the select, but P4 and P5 are in the group by:
The text was updated successfully, but these errors were encountered: