problems with django raw query parameters - django

I was trying to make a custom raw query for a model and i get this error:
DatabaseError: error de sintaxis en o cerca de
«E'positions_statusrecord'» LINE 1: SELECT id FROM
E'positions_statusrecord' WHERE "type"=E'Leav...
Here is the raw query i'm trying to use (it's a manager method):
def get_status_ids(self, model):
"""
This query returns the latest statuses ids for each entry
of "model" in StatusRecord.
"""
db_table = self.model._meta.db_table
model_type = model.get_status_type()
raw_query = (
"SELECT id "
"FROM %s "
"WHERE \"type\"=%s AND "
"(identifier,date_time) IN "
"( "
"SELECT identifier, Max(date_time) "
"FROM %s "
"WHERE \"type\"=%s "
"GROUP BY identifier"
")"
)
params = (db_table, model_type, db_table, model_type, )
return self.raw(raw_query, params)
I've tried with a simpler query (just a SELECT ... FROM ..) and had the same problem. It seems to be that raw queries couldn't have the FROM part completed with a parameter.
Am i right? or have i made a mistake and i'm not finding it?
I'm using postgreSQL 8.4.10, django 1.3 and python 2.6.
I've searched information about raw queries parameters to see if there are some forbidden formatting options, but i didn't find anything that helps me.
Does anyone knows what's causing this error?

It seems to be that raw queries couldn't have the "FROM" part completed with a parameter.
Yes, the ORM will quote the string argument making it ... FROM 'some_table' ....
Since the db_table parameter is trusted (not originated from user input), you can do something like:
raw_query = (
"SELECT id "
"FROM %s "
"WHERE \"type\"=%%s AND "
"(identifier,date_time) IN "
"( "
"SELECT identifier, Max(date_time) "
"FROM %s "
"WHERE \"type\"=%%s "
"GROUP BY identifier"
")"
) % (db_table, db_table)
return self.raw(raw_query, (model_type, model_type))
Since Django Aggregation can be used in filters, probably you can get the same results without resorting to raw SQL (look also the in lookup example).
Look if you can replace raw() with QuerySet.extra() and SQL IN with EXISTS.

Related

Add field value to datefield in django

Parent Model:
id = auto_generated
add_me = IntegerField()
Child Model:
id = ForeignKey(Parent)
my_date= DateTime(auto_now_add=True)
and,
today = django.util.timezone.now()
time = today - timedelta(days=10)
now I want to retrieve records as:
child.objects.filter(my_date__lte= time +
(timedelta(days=1)*F('id__add_me')))
Everthing works fine except:
(timedelta(days=1)*F('id__add_me'))
I am using MYSQL:
I get:
django.db.utils.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
'* `parent`.`add_me`))))' at line 1")
Query Generated is like:
SELECT* FROM `child INNER JOIN `parent` ON
(`child`.`id` = `parent`.`id`) WHERE
( `child`.`my_date` <= ((2018-07-30 09:11:18.670900
+ (INTERVAL '86400.000000' SECOND_MICROSECOND * `parent`.`add_me`))))
As you can see * (multiplication) is with INTERVAL. I hard coded query putting the parent.add_me inside the INTERVAL and got it right, how can I do so via Django? i.e. DATE_ADD in django
I want to reduce days from a datetime field, where days are stored in master table field.
Maybe it doesn't work with MYSQL, so please provide an alternative solution to such.
UPDATED:
Somehow I found error by writing MYSQL query as:
SELECT * FROM child INNER JOIN parent ON" \
child.id = parent.id WHERE
child.my_date<= '" + str(time) + \
"' + INTERVAL parent.add_me DAY "
The problem was with single quotes (') i.e. in mysql for <= the datetime shall be within single quotes else won't work. i.e.
2018-07-30 09:11:18.670900 shall be written as
'2018-07-30 09:11:18.670900' if adding with INTERVAL,
But as queries are generated by Django, how do I achieve that?

Django raw Query aggreation function

I need to write django raw query function to get the sum value and then write to the csn file.
I write my query
for time in Tracking_details.objects.raw('SELECT *,sum=SUM(work_time) FROM structure_tracking_details WHERE employee_id='+ employee_id + ' GROUP BY project_structure ') :
writer.writerow([ time.project_structure,time.sum ])
it tells
no such column: sum
How do I write the query correctly?
Replace sum=SUM(work_time) with SUM(work_time) AS sum.
BTW, employee_id='+ employee_id + ' is a very poor way of building queries. And you should not do it. It makes your query prone to SQL Injection as Django doesn't check whatever query you pass in raw() function. You can pass parameters to the raw query like this -
Tracking_details.objects.raw('SELECT *, SUM(work_time) AS sum FROM structure_tracking_details WHERE employee_id = %s GROUP BY project_structure', [employee_id])
More details.

Qt Query Top Number Record Selecting

I have a query that should request the top X number of records using the Qt framework to actually make the request to the SQL database. I have verified when I place an hard-coded number the query is successful, but when I attempt to bind to it I get an error.
query.prepare("SELECT TOP :numberToSelect"
" deviceId"
" , latitude"
" , longitude"
" , [timeStamp]"
" FROM Positions "
" WHERE [address] = ''"
" ORDER BY [timeStamp] DESC");
query.bindValue(":numberToSelect", numberMissing);
The variable numberMissing is an unsigned short which is passed in. Upon execution I receive this error:
Unable to execute statement: "[Microsoft][ODBC SQL Server Driver][SQL
Server]Incorrect syntax near '#P1'. [Microsoft][ODBC SQL Server
Driver][SQL Server]Statement(s) could not be prepared. QODBC3: Unable
to execute statement" "SELECT TOP ? deviceId , latitude ,
longitude , [timeStamp] FROM Positions WHERE [address] = ''
ORDER BY [timeStamp] DESC"
I do not see what the error would be.
Oracle parameters are signified with a preceding : - SQLServer's closest equivalent would be an # sign. Try changing :numberToSelect to #numberToSelect.
When you do a select top with a variable, the top value needs to be in parenthesis.
Try this:
query.prepare("SELECT TOP (:numberToSelect)"
" deviceId"

psycopg2 strange behavior

from django.db import connection
q = 'some value'
sql1 = 'SELECT * FROM table WHERE field LIKE %%%s%%' % q
sql2 = 'SELECT * FROM table WHERE field LIKE %%'+ q +'%%'
cursor = connection.cursor()
cursor.execute( sql1 ) #why exception: IndexError: tuple index out of range ?
cursor.execute( sql2 ) #works ok
You need to QUOTE properly your SQL arguments.
And by quoting properly I mean using the quote facility provided by DBAPI, not adding a ' around your string, which is useless.
Correct code :
q = "%"+q+"%"
cursor.execute( 'SELECT * FROM table WHERE field LIKE %s', (q,) )
Really correct code :
q = "%"+q.replace("%","%%")+"%"
cursor.execute( 'SELECT * FROM table WHERE field LIKE %s', (q,) )
Suppose q = "a'bc"
First, rewrite this as "%a'bc%"
Then use it as a normal string argument. psycopg will rewrite it as '%a\'bc%' as it should.
If q may contain "%" and you want to search for it, then use the second one.
Using direct string manipulation will almost certainly lead to improper SQL that is vulnerable to SQL Injection attacks (see psycopg2's comments on the subject).
What I think you're looking to do is try and perform a LIKE '%some value%' in django, right?:
from django.db import connection
q = '%some value%'
cur = connection.cursor()
cur.execute("SELECT * FROM table WHERE field LIKE %(my_like)s", {'my_like': q})
As of psycopg2 2.4.1, the SQL that is executed on the server is:
SELECT * FROM table WHERE field LIKE '%some value%'
You need to QUOTE properly your SQL command:
sql1 = "SELECT * FROM table WHERE field LIKE '%%%s%%'" % q
sql2 = "SELECT * FROM table WHERE field LIKE '%"+ q +"%'"
And by quoting properly I mean using single quotes with LIKE expressions.

Can I use parameters for the table name in sqlite3?

I'm having some strange feeling abour sqlite3 parameters that I would like to expose to you.
This is my query and the fail message :
#query
'SELECT id FROM ? WHERE key = ? AND (userid = '0' OR userid = ?) ORDER BY userid DESC LIMIT 1;'
#error message, fails when calling sqlite3_prepare()
error: 'near "?": syntax error'
In my code it looks like:
// Query is a helper class, at creation it does an sqlite3_preprare()
Query q("SELECT id FROM ? WHERE key = ? AND (userid = 0 OR userid = ?) ORDER BY userid DESC LIMIT 1;");
// bind arguments
q.bindString(1, _db_name.c_str() ); // class member, the table name
q.bindString(2, key.c_str()); // function argument (std::string)
q.bindInt (3, currentID); // function argument (int)
q.execute();
I have the feeling that I can't use sqlite parameters for the table name, but I can't find the confirmation in the Sqlite3 C API.
Do you know what's wrong with my query?
Do I have to pre-process my SQL statement to include the table name before preparing the query?
Ooookay, should have looked more thoroughly on SO.
Answers:
- SQLite Parameters - Not allowing tablename as parameter
- Variable table name in sqlite
They are meant for Python, but I guess the same applies for C++.
tl;dr:
You can't pass the table name as a parameter.
If anyone have a link in the SQLite documentation where I have the confirmation of this, I'll gladly accept the answer.
I know this is super old already but since your query is just a string you can always append the table name like this in C++:
std::string queryString = "SELECT id FROM " + std::string(_db_name);
or in objective-C:
[#"SELECT id FROM " stringByAppendingString:_db_name];