SQLAlchemy - check if query found any results - sqlalchemy

How can I check if a query found any results?
result = db.engine.execute(sql, id=foo)
// check if result has rows ...
for row in result:
...
Tried this:
if result is None:
print("reuslt is None!")
and checked length:
print("result len", len(result))

all() may be quite slow for some databases, count() is better but first() is even faster for large databases and complex queries. For example:
x = db.session.query(Post).filter(Post.read==True).first() is not None

rowcount works for me, as a simple way of checking if a query is empty in SQLAlchemy.
results = db.engine.execute(tbl.select(<YOUR-SELECT-QUERY>))
num_results = results.rowcount
if int(num_results) == 0:
print('NO RESULTS FOUND')
else:
print(str(num_results)+' RESULTS FOUND')

len is the better way. You were near:
print("result len", len(result.all()))
You cant access to a BaseQuery len if you dont get all of its elements.
Compare result with None is ok if you want to know if its empty.

I was able to find a way to do this.
Here is the code:
blogs = Post.query.filter_by(subcategory_id=subcategory, category_id=2)
if blogs.count() == 0 :
return redirect(url_for('blogs.travel', subcategory=subcategory))
Hopefully this helps!

I used the code below and worked well. If the query.first() tuple returns a result different from 0 it means there's something in that query.
sql = f"SELECT COUNT(user_id) FROM users_table WHERE user_name = '{user_name}'"
query = engine.execute(sql)
if query.first()[0] != 0:
do_something

The following worked for me:
flag=0
present=True
for i in result:
flag=1
break
if(flag==0)
present=False #No result found

Related

Hash a Select SQLAlchemy query

I have a SQLAlchemy query that I build, such as :
query_one = User.query.filter(User.id == 1) # Note that I don't call .first() or .all() as I want the "select" instance.
I want to store this Select query in such a way that I can retrieve it by having the same query :
stored_queries = {}
stored_queries[hash(query_one)] = query_one
# ... later on:
query_two = User.query.filter(User.id == 1)
if hash(query_two) in stored_queries:
# Execute custom code because it's the same query
Of course, hash in that case does not work, but is there a SQLAlchemy method that works in the same way?
I thought of str(query_one), but that query only consider the request, without the value. I need both.
Thank you in advance.
You can compile the query to get access to the parameters, and use those as part of your key:
def query_key(query):
statement = query_one.statement.compile()
return str(statement), str(statement.params)
query_key(query_one)
('SELECT user.id, ... FROM user WHERE user.id = :id_1', "{'id_1': 1}")
See https://docs.sqlalchemy.org/en/14/core/selectable.html#sqlalchemy.sql.expression.TableClause.compile

mysql queries whose results are not quite right

I have a database :
I want to retrieve data with conditions where the card number is 7689, with product ID 73 or 71.
$this->cekModel->where('card_number', 7689)->where('id_product ', '73')orWhere('id_product', '71')->FindAll();
The result must display 2 data, i.e. which has id = 1 and id = 4 but I only get one data using the query above
Doesn't whereIn() do what you want?
$this->cekModel
->where('card_number', 7689)
->whereIn('id_product', array(71, 73))
->FindAll();
$this->cekModel
->where('card_number', 7689)
->whereIn('id_product', array(71, 73))
->FindAll();
The code above does not work correctly on my console (returns wrong results).
I tried modification and it worked.
$data=['71','73'];
$this->cekModel
->where('card_number', 7689)
->whereIn('id_product', $data)
->FindAll();
Thank you..

MySql try to get information from table

I stack on this error for a long time, I try to find some records by passing the where condition with variable. for some reason the query code that I wrote in python those not get the variable and return this error :
self._connection.handle_unread_result().
raise errors.InternalError("Unread result found").
mysql.connector.errors.InternalError: Unread result found.
and here is the code I am using to function to execute!
def unfollow_user(username, update):
if update == True:
get_list_of_not_following_back()
sql.cur.execute("SELECT user_id FROM not_following_back WHERE username = (%s) AND of_user =
(%s)",(username, current_user[0]))
unfollow_user_id = sql.cur.fetchone()
def unfollow_number_of_follower():
sql.cur.execute("SELECT username,user_id FROM not_following_back WHERE of_user =(%s)",
(current_user[0],))
list_of_user_to_unfollow = sql.cur.fetchmany(number_of_user_to_unfollow)
for each_user_to_unfollow in list_of_user_to_unfollow:
unfollow_user(each_user_to_unfollow[0], False)
I figured out the result to this problem all you need to do is defined your cur as
cur = conn.cursor(buffered=True)
I am not sure why but it work

Rails update multiple record with hash

I need to update my data iteratively.
But the following way I achieved is the way too time-consuming.
Can I update multiple records with an id-value hash?
SUBST = ''.freeze
re = /<p>|<\/p>/m
(1..1000).each do |id|
choice = QuestionChoice.find id
choice.selections.gsub!(re, SUBST)
choice.save! if choice.changed?
end
Update:
Since I found out my code could be improved by using where
Like the following
QuestionChoice.where(id: (1..1000)).each do |choice|
choice.selections.gsub!(re, SUBST)
choice.save! if choice.changed?
end
But now I still need to call save! for every record which will cost much time.
You are hitting the db 1000 times sequentially to get each record separately, try to use single query to get all records you need to update:
SUBST = ''.freeze
re = /<p>|<\/p>/m
QuestionChoice.where('id <= 1000').map do |q|
q.selections.gsub!(re, SUBST)
q.save! if q.changed?
end
I used to face this problem and I solved it. Try to the following:
MySQL 8.0+:
QuestionChoice.where(id: 1..1000).update_all("selections = REGEXP_REPLACE(selections, '<p>|<\/p>', '')")
Others:
QuestionChoice.where(id: 1..1000).update_all("selections = REPLACE(selections, '</p>', '')")
or
QuestionChoice.where(id: 1..1000).update_all %{
selections =
CASE
WHEN selections RLIKE '<p>|<\/p>'
THEN REPLACE(selections,'<p>|<\/p>', '')
END
WHERE selections RLIKE '<p>|<\/p>'
}
IMPORTANT: Try to put a few backlashes (\) to your regex pattern in the clause if needed.

Could not format node 'Value' for execution as SQL

I've stumbled upon a very strange LINQ to SQL behaviour / bug, that I just can't understand.
Let's take the following tables as an example: Customers -> Orders -> Details.
Each table is a subtable of the previous table, with a regular Primary-Foreign key relationship (1 to many).
If I execute the follow query:
var q = from c in context.Customers
select (c.Orders.FirstOrDefault() ?? new Order()).Details.Count();
Then I get an exception: Could not format node 'Value' for execution as SQL.
But the following queries do not throw an exception:
var q = from c in context.Customers
select (c.Orders.FirstOrDefault() ?? new Order()).OrderDateTime;
var q = from c in context.Customers
select (new Order()).Details.Count();
If I change my primary query as follows, I don't get an exception:
var q = from r in context.Customers.ToList()
select (c.Orders.FirstOrDefault() ?? new Order()).Details.Count();
Now I could understand that the last query works, because of the following logic:
Since there is no mapping of "new Order()" to SQL (I'm guessing here), I need to work on a local list instead.
But what I can't understand is why do the other two queries work?!?
I could potentially accept working with the "local" version of context.Customers.ToList(), but how to speed up the query?
For instance in the last query example, I'm pretty sure that each select will cause a new SQL query to be executed to retrieve the Orders. Now I could avoid lazy loading by using DataLoadOptions, but then I would be retrieving thousands of Order rows for no reason what so ever (I only need the first row)...
If I could execute the entire query in one SQL statement as I would like (my first query example), then the SQL engine itself would be smart enough to only retrieve one Order row for each Customer...
Is there perhaps a way to rewrite my original query in such a way that it will work as intended and be executed in one swoop by the SQL server?
EDIT:
(longer answer for Arturo)
The queries I provided are purely for example purposes. I know they are pointless in their own right, I just wanted to show a simplistic example.
The reason your example works is because you have avoided using "new Order()" all together. If I slightly modify your query to still use it, then I still get an exception:
var results = from e in (from c in db.Customers
select new { c.CustomerID, FirstOrder = c.Orders.FirstOrDefault() })
select new { e.CustomerID, Count = (e.FirstOrder != null ? e.FirstOrder : new Order()).Details().Count() }
Although this time the exception is slightly different - Could not format node 'ClientQuery' for execution as SQL.
If I use the ?? syntax instead of (x ? y : z) in that query, I get the same exception as I originaly got.
In my real-life query I don't need Count(), I need to select a couple of properties from the last table (which in my previous examples would be Details). Essentially I need to merge values of all the rows in each table. Inorder to give a more hefty example I'll first have to restate my tabels:
Models -> ModelCategoryVariations <- CategoryVariations -> CategoryVariationItems -> ModelModuleCategoryVariationItemAmounts -> ModelModuleCategoryVariationItemAmountValueChanges
The -> sign represents a 1 -> many relationship. Do notice that there is one sign that is the other way round...
My real query would go something like this:
var q = from m in context.Models
from mcv in m.ModelCategoryVariations
... // select some more tables
select new
{
ModelId = m.Id,
ModelName = m.Name,
CategoryVariationName = mcv.CategoryVariation.Name,
..., // values from other tables
Categories = (from cvi in mcv.CategoryVariation.CategoryVariationItems
let mmcvia = cvi.ModelModuleCategoryVariationItemAmounts.SingleOrDefault(mmcvia2 => mmcvia2.ModelModuleId == m.ModelModuleId) ?? new ModelModuleCategoryVariationItemAmount()
select new
{
cvi.Id,
Amount = (mmcvia.ModelModuleCategoryVariationItemAmountValueChanges.FirstOrDefault() ?? new ModelModuleCategoryVariationItemAmountValueChange()).Amount
... // select some more properties
}
}
This query blows up at the line let mmcvia =.
If I recall correctly, by using let mmcvia = new ModelModuleCategoryVariationItemAmount(), the query would blow up at the next ?? operand, which is at Amount =.
If I start the query with from m in context.Models.ToList() then everything works...
Why are you looking into only the individual count without selecting anything related to the customer.
You can do the following.
var results = from e in
(from c in db.Customers
select new { c.CustomerID, FirstOrder = c.Orders.FirstOrDefault() })
select new { e.CustomerID, DetailCount = e.FirstOrder != null ? e.FirstOrder.Details.Count() : 0 };
EDIT:
OK, I think you are over complicating your query.
The problem is that you are using the new WhateverObject() in your query, T-SQL doesnt know anyting about that; T-SQL knows about records in your hard drive, your are throwing something that doesn't exist. Only C# knows about that. DON'T USE new IN YOUR QUERIES OTHER THAN IN THE OUTER MOST SELECT STATEMENT because that is what C# will receive, and C# knows about creating new instances of objects.
Of course is going to work if you use ToList() method, but performance is affected because now you have your application host and sql server working together to give you the results and it might take many calls to your database instead of one.
Try this instead:
Categories = (from cvi in mcv.CategoryVariation.CategoryVariationItems
let mmcvia =
cvi.ModelModuleCategoryVariationItemAmounts.SingleOrDefault(
mmcvia2 => mmcvia2.ModelModuleId == m.ModelModuleId)
select new
{
cvi.Id,
Amount = mmcvia != null ?
(mmcvia.ModelModuleCategoryVariationItemAmountValueChanges.Select(
x => x.Amount).FirstOrDefault() : 0
... // select some more properties
}
Using the Select() method allows you to get the first Amount or its default value. I used "0" as an example only, I dont know what is your default value for Amount.