I have the following MySQL query which uses subqueries and sums them together.
SELECT *,(SELECT count(`id`) FROM `Texts` WHERE `UserId` =
`Users`.`id`) + (SELECT count(`id`) FROM `Calls` WHERE `UserId` =
`Users`.`id`) as `totalTextsAndCalls` FROM `Users` WHERE `id` IN
(1,2) ORDER BY `totalTextsAndCalls` DESC
This query works when I test manually right now and gives me the results I want.
I'm not sure how you handle subqueries in Sequelize however. I've looked into the Sequelize literals but not sure if this is the only way to do this? I can't seem to get the literal to work either. I will post my attempts at Sequelize writing this shortly if they are needed.
Related
When running the following query on AWS aurora I get the result 1, but I expected 0:
select count(distinct `t`.`input`)
from `db`.`Transactions` as `t`
join `db`.`Users` as `user`
on `user`.`id` = `t`.`userId`
where (
`t`.`documentId` = 'THIS DOESNT EXIST'
)
When omitting the distinct keyword, it correctly returns 0:
select count(`t`.`input`)
from `db`.`Transactions` as `t`
join `db`.`Users` as `user`
on `user`.`id` = `t`.`userId`
where (
`t`.`documentId` = 'THIS DOESNT EXIST'
)
When I run this against a local mysql instance with (almost) the same data, I get 0 with both queries, which is what I would expect.
Is this an AWS Aurora bug? If so, how can I work around this?
Edit: The t.input is of type json. When using a non-json column like documentId or userId I correctly get the expected 0.
Screenshot of the problem:
I have a laravel application that was running an elqouent query with a whereHas method. The method was not returning any data on a virtual machine running mysql 5.7 but was working on 5.6. I got the raw query out of eloquent, here's what it is:
select * from `threads` where `id` = 5053 and exists (select * from `users` inner join `threads_users` on `users`.`id` = `threads_users`.`user_id` where `threads_users`.`thread_id` = `threads`.`id` and `user_id` = 296) limit 1
When I run this sql in mysql 5.6 it will return a single row but when I run it on mysql 5.7 it returns nothing. Is there some feature that was removed between these versions that would break this query?
I am tying to run an update query with a subquery against a MySQL database using ruby. I am using ruby 1.9.3 and rails 4.1.
The query I am trying to create is as below:
UPDATE `items`
SET
`items`.`status_id` = 12
WHERE
`items`.`id` IN (SELECT DISTINCT
`items`.`id`
FROM
`items`
LEFT OUTER JOIN
`statuses` ON `items`.`status_id` = `statuses`.`id`
LEFT OUTER JOIN
`resources` ON `items`.`resource_id` = `resources`.`id`
WHERE
`statuses`.`title` LIKE 'On Loan'
AND `items`.`duedate` < '2015-04-24'
AND `items`.`return_date` IS NULL
ORDER BY `items`.`duedate`)
I can produce this query in ruby using AREL with the code shown below:
# Declare Arel objects
i = Item.arel_table
s = Status.arel_table
r = Resource.arel_table
# This is the AREL query that returns the data
overdues = i.project(i[:id]).
join(s, Arel::Nodes::OuterJoin).on(i[:status_id].eq(s[:id])).
join(r, Arel::Nodes::OuterJoin).on(i[:resource_id].eq(r[:id])).
where(s[:title].matches("On Loan").
and(i[:duedate].lt(DateTime.now.to_date)).
and(i[:return_date].eq(nil))
).
order(i[:duedate])
# Note: You can't chain distinct, otherwise "overdues" becomes a string with the value "DISTINCT".
overdues.distinct
# This creates the update...
u = Arel::UpdateManager.new i.engine
u.table(i)
u.set([[i[:status_id], 10]]).where(i[:id].in(overdues))
This does not work and returns an error message:
ActiveRecord::StatementInvalid: Mysql2::Error: You can't specify target table 'items' for update in FROM clause:
I tried using AR "update_all" but it produces the same SQL and hence the same error.
Item.where(i[:id].in(overdues)).update_all(:status_id => (Status.find_by(:title => "Overdue").id))
Having done some research I have found that you cannot run a update with a subquery that references the table you want to update in MySQL. I have seen a number of posts on this site and the wider internet that detail work arounds.
One suggestion says that the update should use a join instead of a sub query. Having looked at the code behind the update manager it has no "join" so I can't do that.
Another says run this in two parts but I can't see how to because AREL and AciveRecord both chain actions.
The only way I can see of doing this is by aliasing the table and adding an additional select (see below). This isn't great but it would be useful to see if it is possible to do.
UPDATE `items`
SET `status_id` = 10
WHERE `items`.`id` IN (
SELECT x.id
FROM
(SELECT DISTINCT `items`.`id`
FROM `items`
LEFT OUTER JOIN `statuses` ON `items`.`status_id` = `statuses`.`id`
LEFT OUTER JOIN `resources` ON `items`.`resource_id` = `resources`.`id`
WHERE `statuses`.`title` LIKE 'On Loan'
AND `items`.`duedate` < '2015-04-24'
AND `items`.`return_date` IS NULL
ORDER BY `items`.`duedate`) x
);
If I can't get this to work I could adopt two other approaches:
1) I could just hard-code the SQL but I want to use ActiveRecord and reference the models to keep it database agnostic.
2) The other way is to return an instance of all the records and loop through them doing individual updates. This will have a performance issue but I can accept this because its a background job that won't be updating more than a handful of records each day.
Update
I have the AREL query below that produces the subquery in the format I need.
x = Arel::Table.new('x')
overdues = Item.select(x[:id]).from(
Item.select(Item.arel_table[:id]).where(
Status.arel_table[:title].matches("On Loan").and(
Item.arel_table[:duedate].lt(DateTime.now.to_date).and(
Item.arel_table[:return_date].eq(nil))
)
).joins(
Item.arel_table.join(Status.arel_table, Arel::Nodes::OuterJoin).on(
Item.arel_table[:status_id].eq(Status.arel_table[:id])
).join_sources
).joins(
Item.arel_table.join(Resource.arel_table, Arel::Nodes::OuterJoin).on(
Item.arel_table[:resource_id].eq(Resource.arel_table[:id])
).join_sources
).order(Item.arel_table[:duedate]).uniq.as('x')
)
Sadly it returns an error when I use it in my update statement.
TypeError: Cannot visit Item::ActiveRecord_Relation
Having revisited this question I am at the conclusion that it's not possible to do this because of a limitation with MySQL:
ActiveRecord::StatementInvalid: Mysql2::Error: You can't specify target table 'items' for update in FROM clause:
It should be possible to do with other databases (although I haven't tested that).
I could create a temporary table, which is the copy of the original table, reference that and then drop the temporary table like this post suggests:
http://richtextblog.blogspot.co.uk/2007/09/mysql-temporary-tables-and-rails.html. That seems a lot of overhead to do a simple subquery.
What I am going to do is find all the ID's and loop through them and update the records that way (using a simple find and update). This has an overhead but it should only be updating a handful of records each run (no more than 100). The update will be running as a scheduled job outside user working hours so it won't impact performance.
I still find it bizarre that in all other flavours of SQL I have never encountered this problem before. Still you live and learn.
UPDATE:
Since updating my version of MySQL the select statement now works. I had to take out the order by for it to work.
ORDER BY `items`.`duedate`
I am now using version: 5.7.19.
I use MySql, when running below query, I find it acts differently in two box, could any one help me out?
The code is here:
SELECT *
FROM `product` AS `e`
WHERE e.id NOT IN((SELECT `product_id` FROM `sales`))
In one box, it works well and returns the result. In the other box, it shows the error:
[Err] 1242 - Subquery returns more than 1 row
And it works well in both box if remove one pair of (), as below:
SELECT *
FROM `product` AS `e`
WHERE e.id NOT IN(SELECT `product_id` FROM `sales`)
Could anyone tell me the reason, i.e. related to server setting? Can I fix this without modify the sql statements?
The data;
(SELECT `product_id` FROM `sales`)
is treated as the first item in the list to be used by 'NOT IN'.
This must be a single value, so you get the error because multiple rows are returned.
I have the following query in HQL:
update ProjectFile pf1
set pf1.validUntil.id =123
where pf1 = (
select pf from ProjectVersion pv, ProjectFile as pf
where pf.validFrom.sequence <= pv.sequence
and pf.validUntil.sequence >= pv.sequence
and pf.state <> 12
and pf.projectVersion.project.id = 1
and pv.project.id = 1
and pv.id = 12
and pf.id not in (2,3,4)
)
Hibernate parses the query correctly and generates SQL, but the database (MySQL) fails with error:
You can't specify target table 'ProjectFile' for update in FROM clause
The problem seems to be that the table to be updated is queried in the same context. Is there any way to rewrite the HQL query to produce SQL that can be executed in MySQL correctly? The other approach would be to create an intermediate table, which is what exactly I am trying to avoid.
I bumped into the same problem and posted a question here: MySQL/SQL: Update with correlated subquery from the updated table itself.
To solve your problem, you need to join at the UPDATE level, please take a look at the answer to my question.