所以我試圖用group by子句中的引數撰寫一個SQL查詢并讓pyodbc執行它;我有以下架構:
http://sqlfiddle.com/#!18/4e7bb7/2
如果 sqlfiddle 失敗,
CREATE TABLE Persons (
Personid int IDENTITY(1,1) PRIMARY KEY,
Name varchar(255) NOT NULL,
Birthday datetime
);
INSERT INTO PERSONS (NAME, BIRTHDAY)
VALUES
('a','20220101'),
('b','20220102'),
('c','20220103'),
('d','20220104'),
('e','20220105'),
('f','20220106'),
('g','20220108'),
('h','20220110'),
('i','20220111'),
('j','20220112'),
('k','20220113'),
('l','20220114'),
('m','20220115')
我以以下查詢為例,它是有效的 SQL:
select
COUNT(*)
,dateadd(week, datediff(week,0, birthday), 0)
from Persons
group by
dateadd(week, datediff(week,0, birthday), 0)
order by
dateadd(week, datediff(week,0, birthday), 0)
此查詢將按周對用戶的生日進行分組。這只是一個人為的例子。我有與此類似的真實資料。
我正在嘗試撰寫一個 python 函式,它將獲取資料并按周對它們進行分組。我希望這個函式能夠決定一周中的哪一天是一周的開始。我有以下功能:
import pyodbc
def TestSQLServerDB2(dayOfWeekStart=0):
"""Tests the query.
:param: dayOfWeekStart: Int. 0 = Monday, 1 = Tuesday, ... 6 = Saturday
"""
hostname = 'DESKTOPHOST'
database_instance = "test"
db_conn = pyodbc.connect('Trusted_Connection=yes;' r"DRIVER=" "{SQL SERVER}"
";SERVER=" hostname ";DATABASE="
database_instance ";")
targetWeekday = dayOfWeekStart % 7
sql = '''
select
COUNT(*)
,dateadd(week, datediff(week,0, birthday), ?)
from Persons
group by
dateadd(week, datediff(week,0, birthday), ?)
order by
dateadd(week, datediff(week,0, birthday), ?)
'''
params = (targetWeekday ,targetWeekday ,targetWeekday )
cur = db_conn.cursor()
cur.execute(sql, params)
print(cur.fetchall())
運行此函式將產生以下錯誤:
pyodbc.ProgrammingError: ('42000', "[42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Column 'Persons.Birthday' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause. (8120) (SQLExecDirectW); [42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Statement(s) could not be prepared. (8180)")
在執行之前對 SQL 查詢進行字串替換對我來說是微不足道的,而且我不會遇到任何問題;我想知道的是SQL引數化陳述句是否基本上僅限于WHERE子句中的值比較?這是預期的設計嗎?
謝謝
uj5u.com熱心網友回復:
問題是您實際上是將引數傳遞給查詢三次,并且使用不同的GROUP BY引數SELECT。盡管您知道它們是相同的,但服務器卻沒有。實際上,您的查詢是:
select
COUNT(*)
,dateadd(week, datediff(week,0, birthday), @p0)
from Persons
group by
dateadd(week, datediff(week,0, birthday), @p1)
order by
dateadd(week, datediff(week,0, birthday), @p2)
很明顯為什么它不起作用。
解決方案是在每個上使用相同的值。
- 不幸的是,您不能將命名引數與 pyodbc 一起使用,因此已經過時了。
- 您可以使用變數,但這會禁用引數嗅探,這可能是不可取的。
- 您可以將整個內容放在嵌套的子查詢/派生表中。然而嵌套是混亂的,并且使查詢過于復雜。
- 相反,將值放在 a
CROSS APPLY (VALUES中,這意味著您可以在查詢中的任何位置重用它
select
COUNT(*)
,v.birthweek
from Persons
cross apply (values (
dateadd(week, datediff(week,0, birthday), ?)
) ) v(birthweek)
group by
v.birthweek
order by
v.birthweek;
db<>小提琴
在任何情況下,這都是避免重復計算的明智解決方案。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/422496.html
標籤:
