Use the function in order to write only a part of a generator or lambda query using raw SQL.
Write a complete SQL query using the
Entity.select_by_sql()
or methods.
Let’s explore examples of using the raw_sql()
function. Here is the schema and initial data that we’ll use for our examples:
The result can be treated as a logical expression:
select(p for p in Person if raw_sql('abs("p"."age") > 25'))
The raw_sql()
result can be used for a comparison:
q = Person.select(lambda x: raw_sql('abs("x"."age")') > 25)
print(q.get_sql())
SELECT "x"."id", "x"."name", "x"."age", "x"."dob"
FROM "Person" "x"
WHERE abs("x"."age") > 25
Also, in the example above we use raw_sql()
in a lambda query and print out the resulting SQL. As you can see the raw SQL part becomes a part of the whole query.
The can accept $parameters:
x = 25
select(p for p in Person if raw_sql('abs("p"."age") > $x'))
You can change the content of the raw_sql()
function dynamically and still use parameters inside:
x = 1
s = 'p.id > $x'
select(p for p in Person if raw_sql(s))
x = 1
select(p for p in Person if cond)
You can use various types inside the raw SQL query:
x = date(1990, 1, 1)
select(p for p in Person if raw_sql('p.dob < $x'))
Parameters inside the raw SQL part can be combined:
You can even call Python functions inside:
The function can be used not only in the condition part, but also in the part which returns the result of the query:
names = select(raw_sql('UPPER(p.name)') for p in Person)[:]
print(names)
['JOHN', 'MIKE', 'MARY']
But when you return data using the raw_sql()
function, you might need to specify the type of the result, because Pony has no idea on what the result type is:
dates = select(raw_sql('(p.dob)') for p in Person)[:]
print(dates)
['1985-01-01', '1983-05-20', '1995-02-15']
If you want to get the result as a list of dates, you need to specify the result_type
:
dates = select(raw_sql('(p.dob)', result_type=date) for p in Person)[:]
print(dates)
[datetime.date(1986, 1, 1), datetime.date(1984, 5, 20), datetime.date(1996, 2, 15)]
The function can be used in a Query.filter()
too:
x = 25
It can be used inside the without lambda. In this case you have to use the first letter of entity name in lower case as the alias:
x = 25
Person.select().filter(raw_sql('p.age > $x'))
The same parameter names can be used several times with different types and values:
x = 10
y = 31
x = date(1980, 1, 1)
y = 'j'
q = q.filter(lambda p: p.dob > x and p.name.startswith(raw_sql('UPPER($y)')))
persons = q[:]
You can use raw_sql()
in section:
x = 9
Person.select().order_by(lambda p: raw_sql('SUBSTR(p.dob, $x)'))
Or without lambda, if you use the same alias, that you used in previous filters. In this case we use the default alias - the first letter of the entity name:
x = 9
Person.select().order_by(raw_sql('SUBSTR(p.dob, $x)'))
Using the select_by_sql() and get_by_sql() methods
Although Pony can translate almost any condition written in Python to SQL, sometimes the need arises to use raw SQL, for example - in order to call a stored procedure or to use a dialect feature of a specific database system. In this case, Pony allows the user to write a query in a raw SQL, by placing it inside the function or Entity.get_by_sql()
as a string:
Product.select_by_sql("SELECT * FROM Products")
Unlike the method , the method Entity.select_by_sql()
does not return the object, but a list of entity instances.
Parameters are passed using the following syntax: “$name_variable” or “$(expression in Python)”. For example:
x = 1000
y = 500
Product.select_by_sql("SELECT * FROM Product WHERE price > $x OR price = $(y * 2)")
When Pony encounters a parameter within a raw SQL query, it gets the variable value from the current frame (from globals and locals) or from the dictionaries which can be passed as parameters:
globals={'x': 100}, locals={'y': 200})
Variables and more complex expressions specified after the $
sign, will be automatically calculated and transferred into the query as parameters, which makes SQL-injection impossible. Pony automatically replaces $x in the query string with “?”, “%S” or with other paramstyle, used in your database.