MySQL command out of sync when using POW() - mysql

I have this MySQL query that runs perfectly, until I add the POW function to it. I don't understand why I get this error. I've tried to google it but came up empty for a solution.
Original query:
SELECT 86400 /
(NOW() - `created_at`) *
(
(
SELECT COUNT(`Votes`.`voteID`)
FROM `Votes`
WHERE `postID` = `Posts`.`postID`
LIMIT 1
)
+ 0
* 5
) AS `rank`
FROM `Posts`
query with POW():
SELECT POW(
86400
/ (NOW() - `created_at`)
*
(
(
SELECT COUNT(`Votes`.`voteID`)
FROM `Votes`
WHERE `postID` = `Posts`.`postID`
LIMIT 1
)
+ 0
* 5
),
1.8
) AS `rank`
FROM `Posts`
The error I get is #2014 - Commands out of sync; you can't run this command now

While this seems like interesting error in POW() function, you maybe can get around by encapsulating into another subquery:
SELECT POW(rank,1.8)
FROM
(
SELECT (
86400
/ (NOW() - `created_at`)
*
(
(
SELECT COUNT(`Votes`.`voteID`)
FROM `Votes`
WHERE `postID` = `Posts`.`postID`
LIMIT 1
)
+ 0
* 5
)
) AS `rank`
FROM Posts
) tabX

I tried Ollie Jones' suggestion, which worked perfectly for me!
You may be exposing a bug in POW() by passing it an absurdly large, or non-numeric first argument. (NOW() - created_at) probably doesn't do what you think it does. You may want UNIX_TIMESTAMP() - UNIX_TIMESTAMP(created_at) if you hope for a time-difference computation giving a number of seconds as a result. – Ollie Jones

Related

MySQL Query Slow with ORDER BY

So I'm having a problem when I add in ORDER BY date_last_access DESC the whole query slows down to 3secs and without it's about 0.2secs, why is it running so slow and how can I change the query to run faster?
There are also indexes on all the tables and fields used.
Users: 1+ million records
Likes: 5+ million records (over 1 billion in production)
Tables will be growing really fast once in production.
QUERY
SELECT
id,
sid,
first_name,
date_birth,
location,
date_created,
date_last_access,
(3956 * 2 * ASIN(
SQRT(
POWER(
SIN(
({LAT} - latitude) * pi() / 180 / 2
),
2
) + COS({LAT} * pi() / 180) * COS(latitude * pi() / 180) * POWER(
SIN(
({LON} - longitude) * pi() / 180 / 2
),
2
)
)
)) AS distance
FROM
users
WHERE
`id` != {UID} AND
`gender` = {GEND} AND
`date_birth` BETWEEN {DOB_MIN} AND {DOB_MAX} AND
`status` = 'active' AND
(SELECT COUNT(*) FROM likes WHERE likes.judged_user = users.id AND likes.user_id = {UID}) = 0
HAVING distance <= {DIST}
ORDER BY date_last_access DESC
LIMIT {ROWS}
EXPLAIN
1 PRIMARY users ref PRIMARY,Index_2,discovery,index_1 index_1 2 const 226184 Using index condition; Using where; Using filesort
2 DEPENDENT SUBQUERY likes eq_ref PRIMARY,index_1,index_2 PRIMARY 16 const,hello.users.id 1 Using index
INDEXES
LIKES - user_id, judged_user - NORMAL - BTREE
USERS - id, gender, date_birth, status, date_last_access - NORMAL - BTREE
When I order by id instead of date_last_access it seems to run much faster, could it be cause date_last_access is a datetime format?
First try run a EXPLAIN of your query. This will show you what fields and operations are slowing your query. Then try to make joins with indexed columns and filter you resultset with more specific values.
Simplyfying the subquery could be a better way to avoid extra processing time (COUNT):
(SELECT COUNT(*) FROM likes WHERE likes.judged_user = users.id AND likes.user_id = {UID}) = 0
could change to
(SELECT 1 FROM likes WHERE likes.judged_user = users.id AND likes.user_id = {UID} limit 1) IS NULL
Avoiding a subquery could be the best way to improve the performance of the query. You could check what options could be better for your case (an index for likes.user_id is required in this case)
FROM
users
LEFT JOIN (
SELECT distinct judged_user FROM likes WHERE likes.user_id = {UID}
) l ON l.judged_user=users.id
WHERE
`id` != {UID} AND
`gender` = {GEND} AND
`date_birth` BETWEEN {DOB_MIN} AND {DOB_MAX} AND
`status` = 'active' AND
l.judged_user is NULL
You should phrase the FROM clause as:
WHERE `id` <> {UID} AND
`gender` = {GEND} AND
`date_birth` BETWEEN {DOB_MIN} AND {DOB_MAX} AND
`status` = 'active' AND
NOT EXISTS (SELECT 1 FROM likes l WHERE l.judged_user = users.id AND l.user_id = {UID})
HAVING distance <= {DIST}
For this query, you can try two indexes:
LIKES(judged_user, user_id)
USERS(Gender, status, date_birth, id)

Using query result data for another query

The following query works for me. However, is there a way to speed it up (table1/2 contain each more than 300000 entries). I also would like to query more data in the subquery and use the distance just to filter results. The two tables have not much in common except the lat/lon.
SELECT `lat1`,
`lon1`,
(SELECT Sqrt(Pow( 69.1 * ( `lat1` - `lat2` ), 2 )
+ Pow( 69.1 * ( `lon2` - `lon1` ) * Cos( `lat` / 57.3 ), 2 )
) AS
distance
FROM table1
ORDER BY distance
LIMIT 0, 1) AS `test`
FROM `table2`
Thanks in advance

MYSQL view not filling up empty spots to fill 1000

The following query gets the popular questions from the questions asked in the last 2 days. It looks at a feed table to see whats talked about latest, then it searches a tag table to find which one of those is popular.
I only get about 60 results which is great, but I need 1000 results. This means I need to fill up the rest with random questions.
My sql query attempts to do this but does not fill in the rest of the view with more questions not in the feed table.
CREATE
ALGORITHM = UNDEFINED
DEFINER = `root`#`%`
SQL SECURITY DEFINER
VIEW `popular` AS
select
`q`.`name` AS `name`,
`q`.`questionUrl` AS `questionUrl`,
`q`.`miRating` AS `miRating`,
`q`.`imageUrl` AS `imageUrl`,
`q`.`foundOn` AS `foundOn`,
`q`.`myId` AS `myId`
from
(`question` `q`
join `feed` `f` ON ((`q`.`myId` = `f`.`question_id`))
join `tag` `t` ON ((`q`.`myId` = `t`.`question_id`)))
where
(`t`.`name` like '%popular%')
group by `q`.`name`
order by (max(`f`.`timeStamp`) >= (now() - interval 1 day)) desc , (`q`.`myId` is not null) desc
limit 0 , 1000comment
If you need random questions, remove the where clause and move the logic to the order by:
select
`q`.`name` AS `name`,
`q`.`questionUrl` AS `questionUrl`,
`q`.`miRating` AS `miRating`,
`q`.`imageUrl` AS `imageUrl`,
`q`.`foundOn` AS `foundOn`,
`q`.`myId` AS `myId`
from
(`question` `q`
join `feed` `f` ON ((`q`.`myId` = `f`.`question_id`))
join `tag` `t` ON ((`q`.`myId` = `t`.`question_id`)))
group by `q`.`name`
order by (max(`f`.`timeStamp`) >= (now() - interval 1 day)) desc ,
max(`t`.`name` like '%popular%') desc,
rand()
limit 0 , 1000;

Sub query or Join which is the optimal solution?

i've 2 tables, 1 user table and a table where the
outgoing emails are queued. I want to select the users
that are not online for a certain amount of time
and send them an email. I also want that, if they
already received such an email in the last 7 days
or have an scheduled email for the next 7 days, that
they are not selected.
I have 2 queries, which i think would be great if
they are working with subqueries.
As an area of which i'm not an expert in, i would
like to kindly invite you to either,
Build a subquery of the second query
Make a JOIN and exclude the second query results.
I would be far more then happy :)
Thank you for reading
SELECT
`user_id`
FROM
`user`
WHERE
DATEDIFF( CURRENT_DATE(), date_seen ) >= 7
The results of the second query should be excluded
from the query above.
SELECT
`mail_queue_id`,
`mail_id`,
`user_id`,
`status`,
`date_scheduled`,
`date_processed`
FROM
`mail_queue`
WHERE
(
DATEDIFF( CURRENT_DATE(), date_scheduled ) >= 7
OR
DATEDIFF( date_scheduled, CURRENT_DATE() ) <= 7
)
AND
(
`mail_id` = 'inactive_week'
AND
(
`status` = 'AWAITING'
OR
`status` = 'DELIVERED'
)
)
SOLUTION
SELECT
`user_id`
FROM
`user` as T1
WHERE
DATEDIFF( CURRENT_DATE(), date_seen ) >= 7
AND NOT EXISTS
(
SELECT
`user_id`
FROM
`mail_queue` as T2
WHERE
T2.`user_id` = T1.`user_id`
AND
(
DATEDIFF( CURRENT_DATE(), date_scheduled ) >= 7
OR
DATEDIFF( date_scheduled, CURRENT_DATE() ) <= 7
AND
(
`mail_id` = 'inactive_week'
AND
(
`status` = 'AWAITING'
OR
`status` = 'DELIVERED'
)
)
)
)
YOu can select the users who match the first criterion (not having logged on in the past seven days) and then "AND" that criterion to another clause using "NOT EXISTS", aliasing the same table:
select * from T where {first criterion}
and not exists
(
select * from T as T2 where T2.userid = T.userid
and ABS( DATEDIFF(datescheduled, CURRENT_DATE()) ) <=7
)
I'm not familiar with the nuances of the mysql DATEDIFF, i.e. whether it matters which date value appears in which position, but the absolute value would make it so that if the user had been sent a notice in the past 7 days or is scheduled to receive a notice in the next seven days, they would satisfy the condition, and thereby fail the NOT EXISTS condition, excluding that user from your final set.

How to get mysql random integer range?

I am trying to generate a random integer for each row I select between 1 and 60 as timer.
SELECT downloads.date, products.*, (FLOOR(1 + RAND() * 60)) AS timer
I have searched and keep coming up to this FLOOR function as how to select a random integer in a range. This is giving me a 1 for every row.
What am I missing?
I am on mysql 5.0.75
Heres the rest of the query I belive it might be a nesting issue
SELECT *
FROM (
SELECT downloads.date, products.*, FLOOR(1 + (RAND() * 60)) AS randomtimer,
(
SELECT COUNT( * )
FROM distros
WHERE distros.product_id = products.product_id
) AS distro_count,
(SELECT COUNT(*) FROM downloads WHERE downloads.product_id = products.product_id) AS true_downloads
FROM downloads
INNER JOIN products ON downloads.product_id = downloads.product_id
) AS count_table
WHERE count_table.distro_count > 0
AND count_table.active = 1
ORDER BY count_table.randomtimer , count_table.date DESC LIMIT 10
This is working for me. Your mysql version maybe?
SELECT id, (FLOOR( 1 + RAND( ) *60 )) AS timer
FROM users
LIMIT 0 , 30
The output of the RAND function will always be a value between 0 and 1.
Try this:
SELECT downloads.date, products.*, (CAST(RAND() * 60 AS UNSIGNED) + 1) AS timer
Old question, but always actual problem.
Here a way to create a MySQL function random_integer() based on manual :
CREATE FUNCTION random_integer(value_minimum INT, value_maximum INT)
RETURNS INT
COMMENT 'Gets a random integer between value_minimum and value_maximum, bounds included'
RETURN FLOOR(value_minimum + RAND() * (value_maximum - value_minimum + 1));
SELECT ALL random_integer(1, 60) AS timer;
I'm running your query and it does give me a random number for each row.... maybe has something to do with the name of the random (timer)?
You can increase the number multiplied by the number of records in the table.
SELECT id,
(FLOOR( (SELECT MIN(id) FROM your_table ) + RAND( ) * 1000000 ) ) AS timer
FROM your_table
LIMIT 0 , 30