I'm building my own advertisement platform, and I have a little problem. How can I show my ads an equal number of times?
So for example:
Name | Views
Ads 1 | 100
Ads 2 | 98
Ads 3 | 99
So my system need to show the ads with the least views, in this case "Ads 2 or Ads 3".
So all my ads follow each others views. So when my 3 ads have 3.000 views total, there should be 1.000 views on every view.
I'm coding in PHP, and I don't have an example, because I need inspiration how to fix my problem.
Select your least viewed add like this:
SELECT * FROM ads ORDERBY views ASC LIMIT 0, 1
This way, all the ads with less views will slowly catch up.
-- Edit, using your next requirement
probabilityForHighestScore = 30;
random = rand(0, 100);
if (random > probabilityForHighestScore)
SELECT * FROM ads ORDERBY views ASC LIMIT 0, 1
else
SELECT * FROM ads ORDERBY score DESC LIMIT 0, 1
If you need something else, you'd better explain you whole requirement first. Because if it is not clear for you, it won't be clear in your question, and the answers won't do what you want.
I'm assuming you have a database table containing information about these ads. You could add, if you don't already have it, a views field to that table. Then, whenever you need to display an ad, you just grab the one with the lowest view count, add 1 to it's view counter, and display the ad.
Edit:
The problem with #MarvinLabs solution, as I explain in the comments, is that it's giving a huge bonus to a single record.
Let's say you have 50 separate ads in your system. Let's also say that your highest scoring record has a score of 9.9/10, and your second highest scoring record has a score of 9.8/10. Both of these are very high scoring items, but if you use #MarvinLabs code, the highest scoring record will get 30% of all views, while the second highest scoring record will get 1.4% of all views (70 percent of all views divided across the 49 non-highest scoring ads).
What you might want to consider is allowing for a larger range of high scoring ads to be included. You can do this in any one of three ways:
First, you can set a threshold, or multiple thresholds, which divide a certain percentage of views to certain ranges of scores. For example, you could have it so that ads which score more than 9/10 get 30% of all views. You would do that like this:
$random = rand(1,100);
if ($random > 30) {
$sql = "SELECT * FROM ads WHERE score >= 9 ORDER BY views ASC";
} else {
$sql = "SELECT * FROM ads WHERE score < 9 ORDER BY views ASC";
}
The problem with this is that if you don't have any ads with a score above 9, you won't get anything back. For that reason, you probably don't want to use this method.
Second, you could spread your 30% of views across the top 5 or 10 ads:
SELECT *
FROM ads
WHERE id IN
(SELECT id
FROM ads
ORDER BY score DESC
LIMIT 10)
ORDER BY views ASC;
This solves the problem of "what if I don't have any records above the threshold" while still spreading the "high score bonus" across more than just a single record. The problem with this, if you consider it a problem that is, is that it doesn't scale with the volume of ads you have on record. Whether you have 10 records or 10,000 records, you'll still give the bonus to just 10 (or 20, or 50.. whatever you set) records.
If you want to scale, you'll want the third solution.
The third solution is to set your limit based on a percentage of the total number of records in the table. Since MySQL doesn't have a built-in way of handling this, you'll need to workaround this in one of two ways:
One way to do it the lazy way and run two queries - one to get the current record count, and another to create a query based on it. For example:
$query1 = "SELECT COUNT(*) FROM ads";
//store result in $count
$percentage = round($count * 0.10); //get 10% of records
$query2 = "SELECT * FROM ads WHERE id IN " .
"(SELECT id " .
" FROM ads " .
" ORDER BY score DESC " .
" LIMIT " . $percentage . ") " .
"ORDER BY views ASC"
A better way would be to avoid the second round-trip to the database and use a prepared statement:
SELECT #percentage := ROUND(COUNT(*) * 10/100) FROM ads;
PREPARE PERCENTAGE FROM
SELECT *
FROM ads
WHERE id IN
(SELECT id FROM ads
ORDER BY score DESC
LIMIT ?)
ORDER BY views ASC;
EXECUTE PERCENTAGE USING #percentage;
Related
Lets start by saying that I cant use INDEXING as I need the INSERT, DELETE and UPDATE for this table to be super fast, which they are.
I have a page that displays a summary of order units collected in a database table. To populate the table an order number is created and then individual units associated with that order are scanned into the table to recored which units are associated with each order.
For the purposes of this example the table has the following columns.
id, UID, order, originator, receiver, datetime
The individual unit quantities can be in the 1000's per order and the entire table is growing to hundreds of thousands of units.
The summary page displays the number of units per order and the first and last unit number for each order. I limit the number of orders to be displayed to the last 30 order numbers.
For example:
Order 10 has 200 units. first UID 1510 last UID 1756
Order 11 has 300 units. first UID 1922 last UID 2831
..........
..........
Currently the response time for the query is about 3 seconds as the code performs the following:
Look up the last 30 orders by by id and sort by order number
While looking at each order number in the array
-- Count the number of database rows that have that order number
-- Select the first UID from all the rows as first
-- Select the last UID from all the rows as last
Display the result
I've determined the majority of the time is taken by the Count of the number of units in each order ~1.8 seconds and then determining the first and last numbers in each order ~1 second.
I am really interested in if there is a way to speed up these queries without INDEXING. Here is the code with the queries.
First request selects the last 30 orders processed selected by id and grouped by order number. This gives the last 30 unique order numbers.
$result = mysqli_query($con, "SELECT order, ANY_VALUE(receiver) AS receiver, ANY_VALUE(originator) AS originator, ANY_VALUE(id) AS id
FROM scandb
GROUP BY order
ORDER BY id
DESC LIMIT 30");
While fetching the last 30 order numbers count the number of units and the first and last UID for each order.
while($row=mysqli_fetch_array($result)){
$count = mysqli_fetch_array(mysqli_query($con, "SELECT order, COUNT(*) as count FROM scandb WHERE order ='".$row['order']."' "));
$firstLast = mysqli_fetch_array(mysqli_query($con, "SELECT (SELECT UID FROM scandb WHERE orderNumber ='".$row['order']."' ORDER BY UID LIMIT 1) as 'first', (SELECT UID FROM barcode WHERE order ='".$row['order']."' ORDER BY UID DESC LIMIT 1) as 'last'"));
echo "<td align= center>".$count['count']."</td>";
echo "<td align= center>".$firstLast['first']."</td>";
echo "<td align= center>".$firstLast['last']."</td>";
}
With 100K lines in the database this whole query is taking about 3 seconds. The majority of the time is in the $count and $firstlast queries. I'd like to know if there is a more efficient way to get this same data in a faster time without Indexing the table. Any special tricks that anyone has would be greatly appreciated.
Design your database with caution
This first tip may seems obvious, but the fact is that most database problems come from badly-designed table structure.
For example, I have seen people storing information such as client info and payment info in the same database column. For both the database system and developers who will have to work on it, this is not a good thing.
When creating a database, always put information on various tables, use clear naming standards and make use of primary keys.
Know what you should optimize
If you want to optimize a specific query, it is extremely useful to be able to get an in-depth look at the result of a query. Using the EXPLAIN statement, you will get lots of useful info on the result produced by a specific query, as shown in the example below:
EXPLAIN SELECT * FROM ref_table,other_table WHERE ref_table.key_column=other_table.column;
Don’t select what you don’t need
A very common way to get the desired data is to use the * symbol, which will get all fields from the desired table:
SELECT * FROM wp_posts;
Instead, you should definitely select only the desired fields as shown in the example below. On a very small site with, let’s say, one visitor per minute, that wouldn’t make a difference. But on a site such as Cats Who Code, it saves a lot of work for the database.
SELECT title, excerpt, author FROM wp_posts;
Avoid queries in loops
When using SQL along with a programming language such as PHP, it can be tempting to use SQL queries inside a loop. But doing so is like hammering your database with queries.
This example illustrates the whole “queries in loops” problem:
foreach ($display_order as $id => $ordinal) {
$sql = "UPDATE categories SET display_order = $ordinal WHERE id = $id";
mysql_query($sql);
}
Here is what you should do instead:
UPDATE categories
SET display_order = CASE id
WHEN 1 THEN 3
WHEN 2 THEN 4
WHEN 3 THEN 5
END
WHERE id IN (1,2,3)
Use join instead of subqueries
As a programmer, subqueries are something that you can be tempted to use and abuse. Subqueries, as show below, can be very useful:
SELECT a.id,
(SELECT MAX(created)
FROM posts
WHERE author_id = a.id)
AS latest_post FROM authors a
Although subqueries are useful, they often can be replaced by a join, which is definitely faster to execute.
SELECT a.id, MAX(p.created) AS latest_post
FROM authors a
INNER JOIN posts p
ON (a.id = p.author_id)
GROUP BY a.id
Source: http://20bits.com/articles/10-tips-for-optimizing-mysql-queries-that-dont-suck/
Basically I have a rating website where users rate other people from different schools. Right now I'm trying to do the leaderboard script but I cannot properly get the rating to show. My query is only returning one result. ($helpMe) Essentially I'm declaring the average total since my db doesn't store that, it only stores total number and total votes and divides accordingly.
https://pastebin.com/fVf4B8En here is the main code
I suspect that the culprit is here but not sure how
$helpMe = mysql_query("SELECT `rating_number`, FORMAT( (`total_points` / `rating_number`), 1 ) AS `average_rating` FROM `view_rating` WHERE `status` = 1 ORDER BY `average_rating` DESC");
while ($ratingRow = mysql_fetch_assoc($helpMe)) {
So , I'm struggling here with a question:
Is it possible to make a query in my sql similar to this:
at least 20% of the results from category A
at least 15% of the results from category B
at least 10% of the results from category C
at least 10% of the results from category D
and the other 50% random ( category a,b,c,d,e,f,g, and so on ) ?
I've tried to search a while but didn't find a good answer so I'm hoping that any one here can give a good hint.
Thanks in advance!!
Before anyone asks and give me a thumbs down, I'm asking this so I can profile my website visitors. Its not at all a random question.
PS: the php tag is because sometimes I use php functions to solve this kind of problems and the website is php based
I am not sure what exactly are you trying to do but I think you can solve your problem with different approach , but anyway i thought about your question and the only idea came in my mind is the following :
*supposing your have a total 5000 rows and you want to SELECT only 50 rows of them where these 50 rows distributing according to your percentage .
$limit = 50;
$cat_a_per = $limit *0.2; // 20% of the results
$cat_b_per = $limit *0.1; // 10% instead of yours 15% because 15% is incorrect ( try to sum percentages up :) )
$cat_c_per = $limit *0.1; // 10% of the results
$cat_d_per = $limit *0.1; // 10% of the results
$rest_per = $limit*0.5; // the rest 50%
// Now create a 5 mysql queries like the following :
"Select * From my_table where cat='A' limit $cat_a_per" ..
"Select * From my_table where cat='B' limit $cat_b_per" ..
"Select * From my_table where cat='C' limit $cat_c_per" ..
"Select * From my_table where cat='D' limit $cat_d_per" ..
"Select * From my_table limit $rest_per" ..
Now sum up the results in one array or use UNION and you are good to go ...
I have a pretty simple query,
$query3 = $db->query("SELECT * FROM mybb_ranks WHERE id='1' ORDER by points DESC");
And what it'll return is a database of people who are registered and ranked. Since players points can be randomly changing due to matches, we determine the rank # by assigning it once the value is fetched in a way like this:
$i = 1;
while($row = mysqli_fetch_array($query5))
{
echo "$row[player]'s rank is $i";
$i++;
}
As you can see, it orders the player's by their points, but determines the rank # from a variable that adds after displaying every rank. However, in each of the user profiles, I would like to display their rank as well. This is a bit more difficult, because I need a certain way to count the amount of rows the query has to go through in order to get to the certain player. So for instance, if PlayerB is ranked at #5, I would need a way to display that on his own profile. For this to happen, I imagine the query would need to be altered to be able to count each individual row (4 rows) before it reaches the certain player on the 5th row. I was wondering, how would I go about this?
Try this:
UPDATE mybb_ranks
LEFT JOIN (
SELECT
player,
#rank:=#rank+1 as current_rank
FROM mybb_ranks
WHERE id='1'
ORDER BY points DESC
) AS t
ON mybb_ranks.player = t.player
SET mybb_ranks.rank = t.current_rank
That means you have to create additional column rank in your mybb_ranks table.
This query will update the rank of user each time you generate your ranks list.
So when you need to show user's rank in his profile page you just request it from the table:
SELECT rank
FROM mybb_ranks
WHERE player = :player_id
if you want it more dynamic, you can run this UPDATE query every time when you generate your player profile page, right before SELECT rank.
i have a table i get cars form databases and i list it in this table:
$row_id=$_GET["id"];
$solK = ($row_id-1) * 9;
$sagK = ($row_id) * 9;
$sorgu2 = mysql_query("SELECT * FROM Car WHERE Car_ID > '$solK' AND Car_ID < '$sagK'");
Every page have 9 cars i use id for sort these cars but when i delete a car (for example Carid=5) in first page have 8 cars but other pages have 9 cars how can i get first N values without CarId from databases can you explain with sql codes.
Add a LIMIT to your query.
For example
SELECT * FROM tbl LIMIT 0, 9
will select the first 9 entries from tbl.
In order to match your query and preserve the ordering I'd state it as
SELECT * FROM Car ORDER BY Car_ID LIMIT 0, 9
for the first nine rows. For the next nine rows, just increment both numbers by 10 and so on.
Rather than code it like you have done, just use LIMIT:
SELECT * FROM Car LIMIT 0,9
then
SELECT * FROM Car LIMIT 9,9
Use "LIMIT offset, row_count" in you statement
Try this SQL statement SELECT * FROM Car LIMIT '$pageN*$nperpage', '$nperpage'
Where $nperpage will be a number of items per page and $pageN will be a page number (note that in this case page numbering starts with 0).
http://dev.mysql.com/doc/refman/5.0/en/select.html
I assume the other answers (using limit and offset) will be suited for your case. But if you (or anyone else) ever need to improve performance, and need to manage fast queries for more than the first few pages, you should implement paging like this:
SELECT f1, f2, ...
FROM tbl
WHERE Car_ID > $id
ORDER BY Car_ID
LIMIT 10