(using django 1.11.2, python 2.7.10, mysql 5.7.18)
The following SQL 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
);
Runs and returns the following result (as expected):
+== id ==+== average_time_of_day ==+
|= 9422 =|===== 20:42:22.8695 =====|
(This is run from HeidiSQL)
Doing something similar (I think! but something is obviously wrong) via Django:
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 '',
]
)
Doing
print average_time_of_day.query
Outputs:
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
);
And Django returns with the following error:
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")
Any idea what I am doing wrong?
Right.
This one will teach me not to try and:
This was not working:
Notice the
'INNER JOIN payment_method_card ON (transaction_transaction.card_id=payment_method_card.id) ' if profile_pk else ''
and'AND payment_method_card.profile_id=' + str(profile_pk) if profile_pk else ''
in theparams
sent to the raw() method. Kind of dynamic?... But this works:
So could Django not like at all the dynamic building of
params
? I'd be very glad to know the answer... I still suspect I did something wrong, though ... Could this have anything to do with SQL injection protection?Apparently Django was wrapping the
INNER JOIN
expressions in single quotes - hence causing MySQL to reject the query. Which actually looked like this, even thoughprint average_time_of_day.query
was not saying anything about it: