I'm asking you for some advice. I have a website where I have videos and users can give them thumbs up and thumbs down. Their saved in a single table. Currently I have three sql queries to get the count of thumbs up, the count of thumbs down and what the logged in user gave (if he did).
And now I'm thinking about making that more performance, but I don't know what is better, since I want to keep the count of queries down.
Method 1) Keep these three queries as they are:
SELECT COUNT(*) as rowcount FROM `videolikes` WHERE `vid` = 'gt6w_RZfs5yx' AND `thumb` = '1' LIMIT 1
SELECT COUNT(*) as rowcount FROM `videolikes` WHERE `vid` = 'gt6w_RZfs5yx' AND `thumb` = '0' LIMIT 1
SELECT * FROM `videolikes` WHERE `vid` = 'gt6w_RZfs5yx' AND `uid` = '1' LIMIT 1
Method 2) Make one query with sub queries (something like that (it doesn't work how it is here)):
SELECT *, (SELECT COUNT(*) as rowcount FROM `videolikes` WHERE `vid` = 'gt6w_RZfs5yx' AND `thumb` = '1' LIMIT 1) as thumbsups, (SELECT COUNT(*) as rowcount FROM `videolikes` WHERE `vid` = 'gt6w_RZfs5yx' AND `thumb` = '0' LIMIT 1) as thumbsdowns FROM `videolikes` WHERE `vid` = 'gt6w_RZfs5yx' AND (`uid` = '1' OR `uid` = NULL)
Method 3) Your own idea, maybe?
Tell me what you think and give some code (if you want).
Best Regards
Charlotte
edit: I'll add some more information:
vid is the id of the video. Everything about the likes is stored in this table, referenced to the video with the VideoID (vid). uid is the UserID who gave the like (or dislike). That means there isn't only the likes and dislikes of one video in this table. To know which like and dislike is for which video, the like will be stored with the videoid.
Or you could use a single query for the up/down votes:
SELECT SUM(thumb = 1) AS upvote, SUM(thumb = 0) AS downvote, ....
MySQL will take the boolean true/false results of those thumb = X tests, convert to integer 0 or 1, and then sum them up
You can combine the first two queries like that:
SELECT
SUM(IF(`thumb` = 1, 1, 0)) AS rowcountthumb0,
SUM(IF(`thumb` = 0, 1, 0)) AS rowcountthumb1
FROM `videolikes` WHERE `vid` = 'gt6w_RZfs5yx'
Since the last query seems to be semantically different, I would keep it separate from the one mentioned here for clarity.
Related
Im looking to display rolls from a MySQLi but I would like to display one yes and one no... example
If I use this code:
$sqldisplay = $mysqli->query("SELECT `id` FROM `albums` ORDER BY `id` DESC LIMIT 5");
while ($rowdisplay = $sqldisplay->fetch_assoc()) {
echo $rowdisplay['id'].'<br>';
}
It will display
10
9
8
7
6
But im looking to display it like this:
10
8
6
4
2
Is it posible? And if so, how can it be done?
Thanks for the help! :D
To display alternating rows, first double your limit.
$sqldisplay = $mysqli->query("SELECT `id` FROM `albums` ORDER BY `id` DESC LIMIT 10");
Then use a boolean switch to determine whether each row will be displayed.
$display = true;
while ($rowdisplay = $sqldisplay->fetch_assoc()) {
if ($display) echo $rowdisplay['id'].'<br>';
$display = !$display; // switch the display on/off
}
This way, you won't have to depend on the value of the ID, something that could produce unexpected results if any IDs are missing due to deleted rows, etc. A numeric ID is a surrogate key which should have no meaning other than uniquely identifying a row.
Using WHERE (id % 2) = 0 would give you only even numbers, and using WHERE (id % 2) > 0 would get you odd numbers.
You can use this along with a subquery that selects MAX(id) and returns either 1 (for odd) or 0 (for even). This will ensure that if the id is even, just even IDs will be returned, and vice-versa, when applied with the logic explained in the paragraph above.
SELECT `id`
FROM `albums`
GROUP BY `id`
HAVING `id` % 2 = (CASE WHEN (SELECT MAX(`id`) FROM `albums`) % 2 = 0 THEN 0 ELSE 1 END)
ORDER BY `id` DESC
LIMIT 5
With Paul's comment below, it's been pointed out that you can clean up the query even more, just doing WHERE id % 2 = (SELECT MAX(id) % 2 FROM albums) instead - this way you shouldn't need any GROUP BY..HAVING.
SELECT `id`
FROM `albums`
WHERE id % 2 = (SELECT MAX(id) % 2 FROM albums)
ORDER BY `id` DESC
LIMIT 5
You can also achieve this in PHP if you wish retrieve both datasets, see Don't Panic's answer for that (although I prefer to do it in MySQL if possible).
MySQL modulus % documentation
when you set id for order by.your result is According to insert each column
you must add column in you table for this .for example you can have column orderBy and you can specify the order of each display column
and then your query same
$sqldisplay = $mysqli->query("SELECT `id` FROM `albums` ORDER BY `orderBy` DESC LIMIT 5");
Simple, just check if the modulo of the ID is 0 (no remainders) to return even numbers.
If you want to return odd numbers, change the modulo to equal 1.
If you want to select odd or even numbers depending on user input, you can easily make an if statement and use Prepared Statements to input the requested number (1 for odd ID rows to be returned, 0 for even rows).
SELECT `id` FROM `albums` WHERE `id` % 2 = 0 ORDER BY `id` DESC LIMIT 5
So your code will be:
$sqldisplay = $mysqli->query("SELECT `id` FROM `albums` WHERE `id` % 2 = 0 ORDER BY `id` DESC LIMIT 5");
while ($rowdisplay = $sqldisplay->fetch_assoc())
{
echo $rowdisplay['id'].'<br>';
}
I want to select a random userid from this query where level = 1 (Normal user) and alive = Yes (User is alive and can play)
$getaid = $sql->query("SELECT userid FROM `users` WHERE `level`='1' AND `alive`='yes'");
I know I can use
$totalusers = mysql_num_rows($getaid);
$randomuserid = rand(1,$totalusers);
to select a random userid but in that code there's a chance that it select a user that is dead (alive = No) or a staff member (level >= 1). is there a better way I can select a random userid without a chance to grab staff members/dead members?
You can do
"SELECT userid FROM `users` WHERE `level`='1' AND `alive`='yes' ORDER BY RAND() LIMIT 1"
Instead of selecting all the records and trying to choose a random one in PHP's side, let the database do the heavy lifting for you:
SELECT userid
FROM `users`
WHERE `level` = '1' AND `alive` = 'yes'
ORDER BY RAND()
LIMIT 1
Your method is about the worst of all possible worlds -- you are bringing all the data back from the database to an array in PHP and then choosing a random value there. But, it should work, because you are only bringing back the appropriate users.
One way of doing this in the database that is simple enough is:
SELECT userid
FROM `users`
WHERE `level`='1' AND `alive` = 'yes'
ORDER BY rand()
LIMIT 1;
However, if you have more than a few hundred rows (or a few thousand), this starts to get too expensive. There are definitely other methods, but bringing all the data back is not a good idea.
One simple fix is to get approximately 100 rows and then randomize them:
SELECT userid
FROM `users` CROSS JOIN
(SELECT COUNT(*) as cnt FROM users `level` = '1' AND `alive` = 'yes') x
WHERE `level` = '1' AND `alive` = 'yes' AND
rand() < 100 * 1 / x
ORDER BY rand()
LIMIT 1;
For performance, you want an index on `users(level, alive).
You can use ORDER BY RAND() LIMIT 1:
$getaid = $sql->query("SELECT userid FROM `users` WHERE `level`='1' AND `alive`='yes' ORDER BY RAND() LIMIT 1");
I am what you would call a 'noob' at MySQL. I can insert/edit/select stuff, but anything more advanced than that stumps me. I have two tables in my database:
Table 'reviews'
id int(11)
review varchar(2500)
game int(11)
user int(11)
title varchar(200)`
and Table 'review_rating'
user int(11)
review int(11) // Corresponds to `reviews.id`
like tinyint(1)
Here is my question: Is it possible to use ORDER BY on the reviews table to order the result by the total number of review_ratings with 'like' = 1 (where 'review' = the id of the 'reviews' table) divided by the total number of review_ratings (where 'review' = the id of the 'reviews' table).
Example:
SELECT *
FROM `reviews`
WHERE `game` = ?
ORDER BY (total number of review_ratings where review = reviews.id and like = 1 /
total number of review_ratings where review = reviews.id)
LIMIT 0, 10
SELECT t.review,
Score = CASE WHEN TotalReviews<> 0 THEN LikedReviews/TotalReviews ELSE NULL END
FROM (
SELECT *,
(SELECT COUNT(*) FROM review_rating WHERE review = r.review) AS TotalReviews ,
(SELECT COUNT(*) FROM review_rating WHERE review = r.review AND like = 1) AS LikedReviews,
FROM review r
WHERE game = ?
)t
ORDER BY t.review, Score
I think it's clearer to put it in the SELECT clause:
SELECT reviews.*,
( SELECT SUM(like) / COUNT(1)
FROM review_ratings
WHERE review = reviews.id
) like_ratio
FROM reviews
WHERE game = ?
ORDER
BY like_ratio DESC
LIMIT 10
;
Notes:
Not tested; I'm away from a MySQL box at the moment.
I think you could move the subquery to the ORDER BY clause if you wanted, but it seems like a useful thing to retrieve, anyway.
I'm not sure how the above will behave if a given review has no ratings. You may need to use a CASE expression to handle that situation.
something like this would order by the total review_rating per review:
select( count(review.id) as 'total' from reviews join review_rating on review.id = review_rating.review group by review.id) order by total
the math is not exactly what you had but hopefully you will get it
so I'm trying to create a ranking system for my website, however as a lot of the records have same number of points, they all have same rank, is there a way to avoid this?
currently have
$conn = $db->query("SELECT COUNT( * ) +1 AS 'position' FROM tv WHERE points > ( SELECT points FROM tv WHERE id ={$data['id']} )");
$d = $db->fetch_array($conn);
echo $d['position'];
And DB structure
`id` int(11) NOT NULL,
`name` varchar(150) NOT NULL,
`points` int(11) NOT NULL,
Edited below,
What I'm doing right now is getting records by lets say
SELECT * FROM tv WHERE type = 1
Now I run a while loop, and I need to make myself a function that will get the rank, but it would make sure that the ranks aren't duplicate
How would I go about making a ranking system that doesn't have same ranking for two records? lets say if the points count is the same, it would order them by ID and get their position? or something like that? Thank you!
If you are using MS SQL Server 2008R2, you can use the RANK function.
http://msdn.microsoft.com/en-us/library/ms176102.aspx
If you are using MySQL, you can look at one of the below options:
http://thinkdiff.net/mysql/how-to-get-rank-using-mysql-query/
http://www.fromdual.ch/ranking-mysql-results
select #rnk:=#rnk+1 as rnk,id,name,points
from table,(select #rnk:=0) as r order by points desc,id
You want to use ORDER BY. Applying on multiple columns is as simple as comma delimiting them: ORDER BY points, id DESC will sort by points and if the points are the same, it will sort by id.
Here's your SELECT query:
SELECT * FROM tv WHERE points > ( SELECT points FROM tv WHERE id ={$data['id']} ) ORDER BY points, id DESC
Documentation to support this: http://dev.mysql.com/doc/refman/5.0/en/sorting-rows.html
Many Database vendors have added special functions to their products to do this, but you can also do it with straight SQL:
Select *, 1 +
(Select Count(*) From myTable
Where ColName < t.ColName) Rank
From MyTable t
or to avoid giving records with the same value of colName the same rank, (This requires a key)
Select *, 1 +
(Select Count(Distinct KeyCol)
From myTable
Where ColName < t.ColName or
(ColName = t.ColName And KeyCol < t.KeyCol)) Rank
From MyTable t
This is a more detailed question as my previous attempt wasn't clear enough. I'm new to MySQL and have no idea about the best way to do certain things. I'm building a voting application for images and am having trouble with some of the finer points of MySQL
My db
_votes
id
voter_id
image_id
_images
id
file_name
entrant_id
approved
_users
id
...
Basically I need to do the following:
tally up all votes that are approved
return the top 5 with the most votes
check if the user has voted on each of these 5 (return Boolean) from another table
I've tried variations of
SELECT i.id, i.file_name, i.total_votes
FROM _images i WHERE i.approved = 1
CASE WHEN (SELECT count(*) from _votes v WHERE v.image_id = i.id AND v.voter_id = ?) > 0 THEN '1' ELSE '0' END 'hasvoted'
ORDER BY i.total_votes DESC LIMIT ".($page*5).", 5
is that something I should try and do all in one query?
This query was working fine before I tried to add in the 'hasvoted' boolean:
SELECT id, file_name, total_votes FROM _images WHERE approved = 1 ORDER BY total_votes DESC LIMIT ".($page*5).", 5
At the moment I'm also storing the vote count in the _images table and I know this is wrong, but I have no idea about how to tally the votes by image_id and then order them.
Let me give this a shot to see if I understand your question:
SELECT i.*,(SELECT COUNT(*) FROM _votes WHERE i.id = image_id) AS total_votes, (SELECT count(*) from _votes where i.id = image_id and user_id = ?) as voted FROM _images AS i WHERE i.approved = 1