(使用django 1.11.2,python 2.7.10,mysql 5.7.18)
以下SQL查询:
average_time_of_day = Transaction.objects.raw(
'''
SELECT
transaction_transaction.id,
sec_to_time(avg(time_to_sec(extract(HOUR_SECOND from transaction_transaction.transaction_datetime))))
AS average_time_of_day
FROM transaction_transaction
INNER JOIN store_store ON (transaction_transaction.store_id=store_store.id)
%s
WHERE (
transaction_transaction.transaction_datetime BETWEEN %s AND %s
AND store_store.company_id=%s
%s
);
''',
[
'INNER JOIN payment_method_card ON (transaction_transaction.card_id=payment_method_card.id) ' if profile_pk else '',
start_datetime,
end_datetime,
company_pk,
'AND payment_method_card.profile_id=' + str(profile_pk) if profile_pk else '',
]
)
运行并返回以下结果(如预期的那样):
print average_time_of_day.query
(这是从HeidiSQL运行的)
通过Django做类似的事情(我认为!但显然有些错误):
SELECT
transaction_transaction.id,
sec_to_time(avg(time_to_sec(extract(HOUR_SECOND from transaction_transaction.transaction_datetime))))
AS average_time_of_day
FROM transaction_transaction
INNER JOIN store_store ON (transaction_transaction.store_id=store_store.id)
INNER JOIN payment_method_card ON (transaction_transaction.card_id=payment_method_card.id)
WHERE (
transaction_transaction.transaction_datetime BETWEEN 2017-08-31 00:00:00 AND 2017-08-31 00:00:00
AND store_store.company_id=2
AND payment_method_card.profile_id=8
);
否则
ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''INNER JOIN payment_method_card ON (transaction_transaction.card_id=payment_meth' at line 7")
输出:
$y = 1;
$period = 3;
$start = date('m/d/Y');
$end = date('m/t/Y');
echo "<table>";
echo '<thead><th>From</th>';
echo '<th>To</th></thead>';
for ($y; $y <= $period; $y++) {
echo '<tr><td>'.$start.'</td>';
echo '<td>'.$end.'</td></tr>';
$getLast = date('d',strtotime($end));
if($getLast >= 28) {
$start = date("m/t/Y", strtotime($start));
$end = date("m/d/Y", strtotime("+15 day", strtotime($end)));
}else {
$start = date("m/d/Y", strtotime("+15 day", strtotime($start)));
$end = date("m/t/Y",strtotime($end));
}
}
echo "</table>";
Django返回时出现以下错误:
From To
09/15/2017 09/30/2017
09/30/2017 10/15/2017
10/15/2017 10/31/2017
知道我做错了吗?
答案 0 :(得分:0)
您是否尝试过使用Django的ORM来构建该查询?它可以使调试更容易。它可能看起来像这样:
Transaction.objects.filter(
store__company_id=company_pk,
payment_method_card__profile_id=profile_pk,
transaction_datetime__range(start_datetime, end_datetime)
)
您可以在查询中使用Django's select_related
and prefetch_related
优化查询,如果需要更细粒度的控制,则可以使用Q() object
。
我不喜欢手动编写SQL语句,所以这有点像一个副本,但我喜欢使用Django给我的工具。
答案 1 :(得分:0)
在SQL字符串中,某些变量必须是字符串。例如,datetime必须在“”或“我不记得但queryset.query
显示您格式化的sql字符串无效的字符串。
所以只需尝试添加''。
答案 2 :(得分:0)
右。
这个会教我不要尝试:
这不起作用:
average_time_of_day = Transaction.objects.raw(
'''
SELECT
transaction_transaction.id,
sec_to_time(avg(time_to_sec(extract(HOUR_SECOND from transaction_transaction.transaction_datetime))))
AS average_time_of_day
FROM transaction_transaction
INNER JOIN store_store ON (transaction_transaction.store_id=store_store.id)
%s
WHERE (
transaction_transaction.transaction_datetime BETWEEN %s AND %s
AND store_store.company_id=%s
%s
);
''',
[
'INNER JOIN payment_method_card ON (transaction_transaction.card_id=payment_method_card.id) ' if profile_pk else '',
start_datetime,
end_datetime,
company_pk,
'AND payment_method_card.profile_id=' + str(profile_pk) if profile_pk else ''
]
)
请注意发送到raw()方法的'INNER JOIN payment_method_card ON (transaction_transaction.card_id=payment_method_card.id) ' if profile_pk else ''
中的'AND payment_method_card.profile_id=' + str(profile_pk) if profile_pk else ''
和params
。有点动态吗?
...但此有效:
if profile_pk:
average_time_of_day = Transaction.objects.raw(
'''
SELECT
transaction_transaction.id,
sec_to_time(avg(time_to_sec(extract(HOUR_SECOND from transaction_transaction.transaction_datetime))))
AS average_time_of_day
FROM transaction_transaction
INNER JOIN store_store ON (transaction_transaction.store_id=store_store.id)
INNER JOIN payment_method_card ON (transaction_transaction.card_id=payment_method_card.id)
WHERE (
transaction_transaction.transaction_datetime BETWEEN %s AND %s
AND store_store.company_id=%s
AND payment_method_card.profile_id=%s
);
''',
[
start_datetime,
end_datetime,
company_pk,
profile_pk
]
)
else:
average_time_of_day = Transaction.objects.raw(
'''
SELECT
transaction_transaction.id,
sec_to_time(avg(time_to_sec(extract(HOUR_SECOND from transaction_transaction.transaction_datetime))))
AS average_time_of_day
FROM transaction_transaction
INNER JOIN store_store ON (transaction_transaction.store_id=store_store.id)
WHERE (
transaction_transaction.transaction_datetime BETWEEN %s AND %s
AND store_store.company_id=%s
);
''',
[
start_datetime,
end_datetime,
company_pk
]
)
那么Django可能不喜欢params
的动态构建吗?我很高兴知道答案......我仍然怀疑我做错了什么,但是......这与SQL注入保护有什么关系吗?
显然Django将INNER JOIN
表达式包装在单引号中 - 因此导致MySQL拒绝查询。实际上看起来像这样,即使print average_time_of_day.query
没有说出任何内容:
SELECT
transaction_transaction.id,
sec_to_time(avg(time_to_sec(extract(HOUR_SECOND from transaction_transaction.transaction_datetime))))
AS average_time_of_day
FROM transaction_transaction
INNER JOIN store_store ON (transaction_transaction.store_id=store_store.id)
'INNER JOIN payment_method_card ON (transaction_transaction.card_id=payment_method_card.id)'
WHERE (
transaction_transaction.transaction_datetime BETWEEN 2017-08-31 00:00:00 AND 2017-08-31 23:59:59
AND store_store.company_id=2
'AND payment_method_card.profile_id=8'
);