Why use SqlAlchemy's func.lower(mystring) vs. mystring.lower()? - python

Look at this answer: Case Insensitive Flask-SQLAlchemy Query
Why is it better to use SQLAlchemy's func.lower(mystring) instead of python's native mystring.lower()?

The context is important.
user = models.User.query.filter(func.lower(User.username) == func.lower("GaNyE")).first()
Here, there is no string with a lower method to call; you are composing a SQL command to execute in the database. func.lower doesn't return a lowercase string; it returns an object that represents SQL code that can be used to produce a lowercase string.
As mgilson points out, there's no need to use func.lower on actual Python values; they are constant for each row the filter will be applied against, but I'm not sure SQLAlchemy is able to detect and optimize such situations. Either of the following
user = models.User.query.filter(func.lower(User.username) == "ganye").first()
user = models.User.query.filter(func.lower(User.username) == "GaNyE".lower()).first()
would produce SQL code like lower(username) = :lower_1 instead of lower(username) = lower(:lower_1), which can make the SQL query more efficient by eliminating a call to lower for each line.

Related

Add non-datetime variables in SQL python as function parameters

I have a function that executes many SQL queries with different dates.
What I want is to pass all dates and other query variables as function parameters and then just execute the function. I have figured out how to do this for datetime variables as below. But I also have a query that looks at specific campaign_names in a database and pulls those as strings. I want to be able to pass those strings as function parameters but I haven't figured out the correct syntax for this in the SQL query.
def Camp_eval(start_date,end_1M,camp1,camp2,camp3):
query1 = f"""SELECT CONTACT_NUMBER, OUTCOME_DATE
FROM DATABASE1
where OUTCOME_DATE >= (to_date('{start_date}', 'dd/mm/yyyy'))
and OUTCOME_DATE < (to_date('{end_1M}', 'dd/mm/yyyy'))"""
query2 = """SELECT CONTACT_NUMBER
FROM DATABASE2
WHERE (CAMP_NAME = {camp1} or
CAMP_NAME = {camp2} or
CAMP_NAME = {camp3})"""
Camp_eval('01/04/2022','01/05/2022','Camp_2022_04','Camp_2022_05','Camp_2022_06')
The parameters start_date and end_1M work fine with the {} brackets but the camp variables, which are strings don't return any results even though there are results in the database with those conditions if I were to write them directly in the query.
Any help would be appreciated!!
Please, do not use f-strings for creating SQL queries!
Most likely, any library you use for accessing a database already has a way of creating queries: SQLite docs (check code examples).
Another example: cur.execute("SELECT * FROM tasks WHERE priority = ?", (priority,)).
Not only this way is safer (fixes SQL Injection problem mentioned by #d-malan in comments), but it also eliminates the need to care about how data is represented in SQL - the library will automatically cast dates, strings, etc. in what they need to be casted into. Therefore, your problem can be fixed by using proper instruments.

is there a method to add harcoded value in sqlalchemy session query [duplicate]

I have a query which looks like this:
query = session.query(Item) \
.filter(Item.company_id == company_id) \
.order_by(Item.id)
It's a pretty basic query. In addition to pulling out the values for the Item, I want to append an additional value into the mix, and have it returned to me. In raw SQL, I would do this:
SELECT *, 0 as subscribed
FROM items
WHERE company_id = 34
ORDER BY id
How can I manually add that value via sqlalchemy?
You'll need to use a literal_column, which looks a bit like this:
sqlalchemy.orm.Query(Item, sqlalchemy.sql.expression.literal_column("0"))
Beware that the text argument is inserted into the query without any transformation; this may expose you to a SQL Injection vulnerability if you accept values for the text parameter from outside your application. If that's something you need, you'll want to use bindparam, which is about as easy to use; but you will have to invent a name:
sqlalchemy.orm.Query(Item, sqlalchemy.sql.expression.bindparam("zero", 0))
As mentioned in the comments of the accepted answer there's a "shorthand" for bindparam() that alleviates the need to come up with a name for the literal bindparam, literal():
Return a literal clause, bound to a bind parameter.
So one does not have to write
session.query(Item, bindparam("zero", 0).label("subscribed"))
but just
session.query(Item, literal(0).label("subscribed"))
without having to worry about quoting etc., if passing strings or such.

Getting error when running a sql select statement in python

I am new to this and trying to learn python. I wrote a select statement in python where I used a parameter
Select """cln.customer_uid = """[(num_cuid_number)])
TypeError: string indices must be integers
Agree with the others, this doesn't look really like Python by itself.
I will see even without seeing the rest of that code I'll guess the [(num_cuid_number)] value(s) being returned is a string, so you'll want to convert it to integer for the select statement to process.
num_cuid_number is most likely a string in your code; the string indices are the ones in the square brackets. So please first check your data variable to see what you received there. Also, I think that num_cuid_number is a string, while it should be in an integer value.
Let me give you an example for the python code to execute: (Just for the reference: I have used SQLAlchemy with flask)
#app.route('/get_data/')
def get_data():
base_sql="""
SELECT cln.customer_uid='%s' from cln
""" % (num_cuid_number)
data = db.session.execute(base_sql).fetchall()
Pretty sure you are trying to create a select statement with a "where" clause here. There are many ways to do this, for example using raw sql, the query should look similar to this:
query = "SELECT * FROM cln WHERE customer_uid = %s"
parameters = (num_cuid_number,)
separating the parameters from the query is secure. You can then take these 2 variables and execute them with your db engine like
results = db.execute(query, parameters)
This will work, however, especially in Python, it is more common to use a package like SQLAlchemy to make queries more "flexible" (in other words, without manually constructing an actual string as a query string). You can do the same thing using SQLAlchemy core functionality
query = cln.select()
query = query.where(cln.customer_uid == num_cuid_number)
results = db.execute(query)
Note: I simplified "db" in both examples, you'd actually use a cursor, session, engine or similar to execute your queries, but that wasn't your question.

Add custom result value to sqlalchemy query [duplicate]

I have a query which looks like this:
query = session.query(Item) \
.filter(Item.company_id == company_id) \
.order_by(Item.id)
It's a pretty basic query. In addition to pulling out the values for the Item, I want to append an additional value into the mix, and have it returned to me. In raw SQL, I would do this:
SELECT *, 0 as subscribed
FROM items
WHERE company_id = 34
ORDER BY id
How can I manually add that value via sqlalchemy?
You'll need to use a literal_column, which looks a bit like this:
sqlalchemy.orm.Query(Item, sqlalchemy.sql.expression.literal_column("0"))
Beware that the text argument is inserted into the query without any transformation; this may expose you to a SQL Injection vulnerability if you accept values for the text parameter from outside your application. If that's something you need, you'll want to use bindparam, which is about as easy to use; but you will have to invent a name:
sqlalchemy.orm.Query(Item, sqlalchemy.sql.expression.bindparam("zero", 0))
As mentioned in the comments of the accepted answer there's a "shorthand" for bindparam() that alleviates the need to come up with a name for the literal bindparam, literal():
Return a literal clause, bound to a bind parameter.
So one does not have to write
session.query(Item, bindparam("zero", 0).label("subscribed"))
but just
session.query(Item, literal(0).label("subscribed"))
without having to worry about quoting etc., if passing strings or such.

Simple SQLAlchemy query filter in python

I'm trying to select all rows in a sql table where the first four characters of a text column match a certain string. (The backend database is a sqlite instance with limited column types, so bear with me)
The code I've written for the select is this:
rows = SECtable.query.filter(str(SECtable.date)[:4] == str(matchingString)).all()
What am I doing wrong here? The query never matches any rows
If you use SECtable.date == 'some_string', this produces an expression (sqlalchemy.sql.expression.BinaryExpression), which will be evaluated when you execute the query.
str(SECtable.date)[:4] == str(matchingString) is evaluated immediately, it produces the string representation of SECtable.date (i'd guess 'SECTable.date'), and compares all but the fist for characters to str(matchingString). so what you're writing here is basically:
'able.date' == str(matchingString)
which will probably evaluate to false, so you end up with filter(False).
sqlalchemy provides a endswith functionality you could use in this case:
rows = SECtable.query.filter(SECtable.date.endswith(matchingString)).all()
You probably want to use SQLAlchemy's implementation of SQL's LIKE.
See the following documentation:
http://docs.sqlalchemy.org/en/rel_0_8/orm/tutorial.html#common-filter-operators
http://docs.sqlalchemy.org/en/rel_0_8/core/sqlelement.html#sqlalchemy.sql.operators.ColumnOperators.like
http://docs.sqlalchemy.org/ru/latest/orm/query.html

Categories