My site is very slow with because of this mysql query.
SELECT content.*,
(SELECT content_views.views FROM content_views WHERE content_views.content = content.record_num) as views ,
(SELECT images.filename FROM images WHERE images.record_num = content.thumbnail) AS thumbfile
FROM content WHERE enabled = 1 $filterAnd
ORDER BY RAND()
LIMIT $from,$max_results
I know the best way is to use it like this:
SELECT name
FROM random AS r1 JOIN
(SELECT CEIL(RAND() *
(SELECT MAX(id)
FROM random)) AS id)
AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1
But i am using multiple mysql tables i have no idea how i can use my query like this someone that can help me ?
Thank you
edit:
I have tried:
SELECT content.*,
(SELECT content_views.views FROM content_views WHERE content_views.content = content.record_num) as views ,
(SELECT images.filename FROM images WHERE images.record_num = content.thumbnail) AS thumbfile
FROM content AS r1 JOIN
(SELECT (RAND() * (SELECT MAX(record_num) FROM content)) AS id) AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1
but now i get the error: Unknown table 'content'
This code selects one random row from content table.
(SELECT
*
FROM
content AS r1
JOIN
(SELECT
CEIL(RAND() * (SELECT
MAX(id)
FROM
content WHERE enabled = 1 $filterAnd)) AS id
) AS r2
WHERE
r1.id >= r2.id AND r1.enabled=1 AND $filterAnd
ORDER BY r1.id ASC
LIMIT 1) randomTable
Now you need to think about this query as an table with name randomTable fields as in content table. Now you can SELECT from it, JOIN it, to do all what you need. Pay attention to $filterAnd - I used it twice. This will work only if $filterAnd contain conditions related to content table.
You have given the table content an alias called r1. You then need to use that alias for references to that particular table:
SELECT r1.*,
(SELECT cv.views
FROM content_views cv
WHERE cv.content = r1.record_num
) as views,
(SELECT i.filename
FROM images i
WHERE i.record_num = r1.thumbnail
) AS thumbfile
FROM content r1 JOIN
(SELECT RAND() * (SELECT MAX(record_num) FROM content) AS id
) r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1
This version has table aliases for many of the tables.
Most of the suggestions so far assume an AUTO_INCREMENT id with no holes. If that does not apply, see my blog for that solution, plus 7 more.
Related
I am trying to run a query to find the count and percentage of artisan based on gender. The query is running absolutely fine on the SQL server 8. But not on my live server which is 4.9.5.
The below is my query.
SELECT industry
, count(*) as cnt
, (count(*)*100.0/sum(count(*))over()) as perc
FROM `artisan_work`
GROUP BY industry
ORDER BY cnt DESC
In any database, you should be able to use:
SELECT aw.industry, count(*) as cnt,
count(*) * 100.0 / tot.cnt as perc
FROM artisan_work aw cross join
(SELECT COUNT(*) as cnt FROM artisan_work) tot
GROUP BY aw.industry
ORDER BY cnt DESC
SELECT industry
, count(*) as cnt
, (count(*)*100.0/(select count(*) from artisan_work )) as perc
FROM artisan_work a
GROUP BY industry
ORDER BY cnt DESC
I've read many answers to this question but none seem to answer in the scenario when you need to pick one random row in a DB of articles, say a wordpress db, where in the wp_posts, you actually have both revisions, trashed and published articles.
Previous answers seems to return blank result if the id is random and the post is not published like in this code
SELECT * FROM wp_posts AS w
JOIN (SELECT (RAND() * (SELECT MAX(id) FROM wp_posts)) AS id) AS r2
WHERE w.id >= r2.id
AND w.post_status = 'publish'
ORDER BY w.id ASC
LIMIT 1
Just use
SELECT *
FROM wp_posts
WHERE post_status = 'publish'
ORDER BY RAND()
LIMIT 1
to get a random record being published.
Your method is intended to be more efficient than sorting all the published articles. The following is similar for only published articles:
SELECT *
FROM wp_postsw CROSS JOIN
(SELECT (RAND() * (SELECT MAX(id) FROM wp_posts WHERE post_status = 'publish')) AS id
) r2
WHERE w.id >= r2.id AND w.post_status = 'publish'
ORDER BY w.id ASC
LIMIT 1;
For performance, you want an index on wp_posts(post_status, id).
That is, you need the condition inside the subquery. And, you need to include the appropriate columns in the WHERE clause.
I have a query that gets me a users rank in a table of scores.
SELECT
*
FROM
(SELECT
*, #rank:=#rank + 1 rank
FROM
(SELECT
user_id, SUM(round_total) TotalPoints
FROM
sx14sp_mem_picks
GROUP BY user_id) s, (SELECT #rank:=0) init
ORDER BY TotalPoints DESC) r
WHERE
user_id = 22234
There is a problem with ties. I have a table field "pick_date" that i would like to use to break ties with. The user who made his picks first beats the tie.
Any ideas?
If sx14sp_mem_picks.pickdate is the field to break ties then in the order by sx14sp_mem_picks subquery, add
min( pickdate) asc
This will put the earliest pickdate first - you have to use MIN() bc you need to use an aggregate function given the use of "group by".
You need to order by the pick date in addition to the total points. However, you are talking about multiple rows per user. So, let's take the last pick date:
SELECT *
FROM (SELECT *, (#rank:=#rank + 1) as rank
FROM (SELECT user_id, SUM(round_total) as TotalPoints, max(pick_date) as max_pick_date
FROM sx14sp_mem_picks
GROUP BY user_id
) s CROSS JOIN
(SELECT #rank := 0) init
ORDER BY TotalPoints DESC, max_pick_date asc
) r
WHERE user_id = 22234;
Does anybody have any ideas how I can get around a #1235 - This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' error?
My query is below ( I've read that I can upgrade mysql but this isn't possible):
$query = #mysql_query("SELECT * FROM posts
WHERE postid NOT IN
( SELECT postid FROM log
ORDER BY posted DESC
LIMIT 10)
ORDER BY (RAND() * Multiplier)
LIMIT 1");
According to this bug, you can use this ugly workaround:
SELECT * FROM t1 WHERE s1 NOT IN
(SELECT * FROM (SELECT s2 FROM t2 ORDER BY s1 LIMIT 1) AS alias)
You can rewrite your query using JOIN:
SELECT *
FROM posts NATURAL LEFT JOIN (
SELECT postid FROM log ORDER BY posted DESC LIMIT 10
) t
WHERE t.postid IS NULL
ORDER BY RAND()
LIMIT 1
Be aware, however, that ORDER BY RAND() is very expensive. Not only must a random value be calculated for each record, but then a sort must be performed on the results. Indexes are of no use.
You would fare better if you had a column col containing unique integers, then with an index on col you can very rapidly obtain a random record with:
SELECT *
FROM posts NATURAL LEFT JOIN (
SELECT postid FROM log ORDER BY posted DESC LIMIT 10
) t JOIN (
SELECT RAND() * MAX(col) AS rand FROM posts
) r ON posts.col >= r.rand
WHERE t.postid IS NULL
LIMIT 1
Note that the uniformity of such "randomness" will depend on the distribution of the integers within col after any other filtering has taken place.
I currently have this
SELECT *
FROM images
WHERE images.id IN (SELECT image_id FROM image_likes WHERE user_id = '1')
UNION
SELECT *
FROM images
WHERE images.user_id = '1' AND upload_type in (4,3) ORDER BY id DESC
And this works great, but now i want it to display the most recent results thats have happend.
For example, User A uploaded a image-> information goes into images with a timestamp. User A then likes someone else's image -> Information goes into image_likes with a timestamp. Now how would i make the two timestamp column's merge together so i can sort them by DESC.
Breif run over of what the query does.
Selects the image information from images where the user has liked a image in image_likes and then it grabs all of the uploads the user has uploaded from images and merges them into a query. What i need is to be able to sort them using the timestamp from both tables.
how about doing this??
SELECT * FROM (
SELECT *
FROM images
WHERE images.id IN (SELECT image_id FROM image_likes WHERE user_id = '1')
UNION
SELECT *
FROM images
WHERE images.user_id = '1' AND upload_type in (4,3) ORDER BY id DESC
) AS a ORDER BY a.timestamp DESC;
OR even better
(SELECT *
FROM images
WHERE images.id IN (SELECT image_id FROM image_likes WHERE user_id = '1'))
UNION
(SELECT *
FROM images
WHERE images.user_id = '1' AND upload_type in (4,3) ORDER BY id DESC)
ORDER BY timestamp DESC
chk this http://dev.mysql.com/doc/refman/5.5/en/union.html
UPDATE
TRY THIS
(SELECT images.id, images_likes.timestamp as timestamp FROM images JOIN images_likes
ON images.id=image_likes.image_id WHERE user_id = '1')
UNION
(SELECT images.id, images.timestamp as timestamp
FROM images
WHERE images.user_id = '1' AND upload_type in (4,3) ORDER BY id DESC)
ORDER BY timestamp DESC
UPDATE
Final query as per your requirement
(SELECT images.id, images.user_id, images.ext, images.upload_type, images_likes.timestamp as timestamp FROM images JOIN images_likes
ON images.id=image_likes.image_id WHERE images_likes.user_id = '1')
UNION
(SELECT images.id, images.user_id, images.ext, images.upload_type, images.timestamp as timestamp
FROM images
WHERE images.user_id = '1' AND upload_type in (4,3) ORDER BY id DESC)
ORDER BY timestamp DESC
I would approach with the following... The "PreQuery" below starts with all images the user likes first, with the max timestamp as a new column "MostRecent". THEN, do a UNION ALL for the next set. The next set is directly from the images table for the user, but LEFT JOINED to the "Liked" images. Then the WHERE clause explicitly excludes those that would have been returned in the first set by using the "iml2.image_id IS NULL". I did this as I wasn't positive on how the union would handle the group by in the first set, but no group by in the second. Ex: If the image was created with date/timestamp of say Mar 3, but also found as a "Like" of Mar 5, I didn't want one instance listed as each distinct date (as union already qualifies distinct implied).
That said, I will have a single prequery result of any image the person liked with its most recent date/time stamp, AND all their own personal images with their respective date/time stamp. Now, its a simple join back to the images table to grab the details (via alias "i2") and we can sort by the PreQuery.MostRecent column, then by the image ID value descending.
SELECT
i2.*
from
( select iml.image_id as id,
max( iml.YourTimeStamp ) as MostRecent
from image_likes iml
where iml.user_id = '1'
group by iml.image_id
UNION ALL
select i.id,
i.ImageTimeStamp as MostRecent
from images i
left join image_likes iml2
on i.id = iml2.image_id
and iml2.user_id = '1'
where i.user_id = '1'
and i.upload_type in ( 4, 3 )
and iml2.image_id is null
) PreQuery
JOIN Images i2
on PreQuery.id = i2.id
order by
PreQuery.MostRecent,
PreQuery.ID desc
Why don't you use a 'OR'?
that way :
SELECT *
FROM images
WHERE images.id IN (SELECT image_id FROM image_likes WHERE user_id = '1')
OR (images.user_id = '1' AND upload_type in (4,3))
ORDER BY id DESC
SELECT *
FROM
( SELECT im.*
, li.timestamp AS ts
FROM images AS im
JOIN image_likes AS li
ON li.image_id = im.image_id
WHERE li.user_id = 1
UNION ALL
SELECT *
, timestamp AS ts
FROM images
WHERE user_id = 1
AND upload_type in (4,3)
) AS tmp
ORDER BY ts DESC