limit the number of a field value in search results - php

I run real state website, which allows different users to add their properties.
When someone searches for a specific criteria, we use a select statement along with the specified conditions to select the matched properties, do the paging bit and display the results.
We use a rating algorithm to rate each property and use it to priorities the displayed properties.
A simplified version:
name type bedrooms user score
green house sale two bedrooms alex 6
Blue one rent three bedrooms jack 6
Blue one sale three bedrooms jack 4
gray one sale three bedrooms jack 6
green one rent three bedrooms jack 6
purple one rent three bedrooms jack 6
green one rent three bedrooms jack 6
green one rent three bedrooms gary 6
Now the problem is that sometimes a few properties have the same score. In these cases I don't want properties from one user to dominate a search result page, I want to set a limit to display a maximum of three properties of any given user in a search result page.
In the example, I don't want the properties owned by jack to dominate the first page, and properties of other users go to second page. This would upset other users and create a bad experience for visitors.
If I wanted to show only one property for a given user, I'd use Group by, but I'm not sure what to limit to a larger number ( three for instance). Is there anything I could do in mysql to achieve this?
EDIT:
Sorry if it wasnt clear enough.
The use field displays the user who added the particular property. A sample query could be
SELECT * FROM properties WHERE type = 'sale' LIMIT 5 ORDER BY score
The result could be five properties, all added by jack. I want to make sure that no more than thee properties added by a particular user, are included in the results. This way properties added by other users would have a chance to be displayed.

Use DISTINCT it will solve your problem.In a table, a column may contain many duplicate values; and sometimes you only want to list the different (distinct) values.The DISTINCT keyword can be used to return only distinct (different) values. Example
SELECT DISTINCT user FROM table_name;

use DISTINCT in your query something like this example
SELECT DISTINCT column_name,column_name from table;

try with this and change string your_table with your table name
SELECT
*
FROM
`your_table`
LEFT JOIN
(SELECT * FROM `your_table` LIMIT 3) as lr on lr.user = `your_table`.user
GROUP BY
user
reference link
UPDATE 2
if you want to order by your score you can use
SELECT
*
FROM
`your_table`
LEFT JOIN
(SELECT * FROM `your_table` ORDER BY score DESC LIMIT 3) as lr on lr.user = `your_table`.user
GROUP BY
user

Related

Group two columns by occurrence and sort by time in MYSQL

I am working with a table that contains a list of uploaded files that will be processed by a Laser Cutter.
To increase efficiency I need to list files that have the same material and colour in order of how many of the same combination occurs. Then order that by the time it was sent.
Here is a very simplified table example:
From the example table above I want to achieve the following results:
6 File Number 6 Plastic Red 9am
4 File Number 4 Plastic Red 10am
5 File Number 5 Plastic Red 10:30am
1 File Number 1 Card Blue 9am
2 File Number 2 Card Blue 9:30am
7 File Number 7 Plastic Purple 8am
3 File Number 3 Card Green 9am
So where both material and colour occur the most, the respective rows are at the top and within that, the earliest file is at the top.
As you can see, red plastic occurs the most so is at the top. Single files are ordered by time only as seen with file 7 and 3.
Ideally I would like to perform this in one MYSQL query but given its complexity I'm not sure that will be possible. Perhaps storing the results and looping through arrays?
I have nearly managed to achieve this with this query:
SELECT *
FROM propellor.pro_files
GROUP BY material, colour
ORDER BY count(*) DESC,
material DESC,
colour DESC,
sent DESC;
Although this seems to be ordered almost correctly it only returns single rows for each material/colour combination.
It's worth noting that the colour column can be null.
For an idea of how I'm grouping them, here's how it will look in practice:
UPDATE: The material / colour groups are ordered correctly now but single files are ordered newest to oldest when I need it the other way around, I have tried playing with sent ASC / DESC but it only affects files in a group.
UPDATE 2: Here is my current full MYSQL query:
SELECT *
FROM propellor.pro_files
INNER JOIN propellor.pro_users ON propellor.pro_files.userid=propellor.pro_users.userid
INNER JOIN (
SELECT material, colour, count(*) AS occ
FROM propellor.pro_files
GROUP BY material, colour
)
AS mcCounts
USING (material, colour)
WHERE status =1 AND laser=1
ORDER BY mcCounts.occ DESC,
material,
colour,
propellor.pro_files.timesent ASC
;
You need to calculate the counts separately, though it can all be done in a single query; this should do it:
SELECT pf.*
FROM propellor.pro_files AS pf
INNER JOIN (
SELECT material, colour, count(*) AS occ
FROM propellor.pro_files
GROUP BY material, colour
) AS mcCounts USING (material, colour)
ORDER BY mcCounts.occ DESC
, material, colour
, pf.sent DESC
;
Edit: Added material, colour to ORDER BY... for when two combinations have the same frequency.
You can try creating count columns in your sql select and then ordering by those counts
select count(material) over partition by material) as materialCount
, count(colour) over partition by colour) as colourCount
, ..... other columns
from propellor.pro_files
order by materialCount desc, colourcount desc

SQL, 2 tables sum of a field

I have 2 tables, student and family.
Half of the students come Sundays, the other half Saturdays
Some families have more than one child.
Families pay fees for the school. Some families because of some critearia have a discount.
"discount" is a field in 'family' table
In a report I need to calculate the sum of all the discounts of all families that take advantage of a discount (by day).
When I do so, if a family has 2 children, the result returns double of the discount, if 3 children 3 x discount....
My Query:
$select_total_discounts =
"SELECT SUM(Discount) AS total_discounts
FROM family, student
WHERE family.Family_ID=student.Family_ID
AND student.Day like '%$Day%' ;" ;
$query= mysql_query($select_total_discounts,$conn) ;
$row = mysql_fetch_assoc($query);
$total_discounts= $row['total_discounts'];
Thank you in advance
If I understood your question correctly, you want to calculate the discounts by family disregarding the amount of students it has. So it'd be like this (change the day value by your variable):
SELECT SUM(Discount) AS total_discounts
FROM family
WHERE family.Family_ID in (select student.Family_ID from student where student.Day like 'Monday')
So it sums the discounts of the families that have at least one student from the specified day. If it has one, two, three or more students, it will not affect the result.
Working SQLFiddle: http://sqlfiddle.com/#!2/9b9793/1
It is not really full answer, but I posted it here, so it would be readable.
I think you are looking for something like UNION:
SELECT sum(value) FROM ((SELECT value FROM table) UNION ALL (SELECT value FROM table2)) sq
UNION merges your tables vertically.

PHP/MySQL - Count number of sales made and display that number and who sold them

I'm working on a PHP application for University which pretends I buy and resell a specific item to/from countries.
I have a table which contains transaction IDs and the names of the countries that made them.
I've been trying to count up the number of times a specific country's name appears in the database table then print out a table on the webpage showing each countries name and the number of times they appear in the table like below, but I can't find any examples of this kind of thing anywhere, they're always too different to be of much help. I would also like to order the table by max to min count and also be able to limit the number of countries shown using radio buttons (which I've already got working).
countryName | numberOfSales
Belize | 10
Brazil | 6
Cameroon | 64
Colombia | 23
Costa Rica | 47
You need to select the country and count, then group by the country. If you want to order it you need to add that on as well.
SELECT
countryName,
count(*) as numberOfSales
FROM
sales
GROUP BY
countryName
ORDER BY
numberOfSales DESC
This query will have 2 columns in the results. The country names and the number of times they appear according to the grouping. We are grouping all of the records by the country name column. In the query, we name the column numberOfSales, so we can use that when ordering it so that the countries will be in order from max to min in numberOfSales.
If you have two tables in your database (MySql in my case), one where you store the different countries and one for the sales/orders.
Table countries:
id INT
country VARHCAR(255)
Table: sales:
id INT
country_id INT
title VARCHAR(255)
Here there is a 1:many relationship between the two tables. One country can have many sales, but a sale can only belong to one country.
You can then fetch the number of sales for specific country by running the following SQL query.
If you want to find the number of sales for Denmark you could do:
SELECT countries.country, COUNT(*) AS numberOfSales
FROM countries
JOIN sales
ON sales.country_id = countries.id
WHERE countries.country = 'denmark';
If you want to see the total number of sales for each country you can use the following SQL query:
SELECT countries.country, COUNT(*) AS numberOfSales
FROM countries
JOIN sales
ON sales.country_id = countries.id
GROUP BY countries.country;
Here the GROUP BY clause will fetch the result for each of the countries in your countries table. You can add LIMIT clause if necessary.
I hope this doesn't complicate things too much. You will thank me later by using two tables (I do not know if you already do. If you do, NICE).
Related to counting identical rows in MySql: Count number of identical rows in MySQL with PHP
Best regards.

Ad weight, giving advertisers a fair piece of the cake

For the project I am currently involved in we have a select number of 'advertiser' groups that can add 'Offers' to our site that are displayed around other products and sometimes are related to the page the customer/buyer is viewing.
The current Ad system is completely random, and gives no preference except when trying to target a specific product. So, if supplier1 has 9 adverts, and supplier2 has 1 advert then supplier1 gets much better value for their money as they get shown 9 out of 10 times.
How we are wanting to change this system is so that supplier1 and supplier2 should technically get the same exposure as each other regardless of the amount of ads they have in the system.
How would you suggest I try and approach this? I have looked at ad weight systems on StackOverflow; however, they don't seem to relate to groups.
SELECT *
FROM advertisments a
INNER JOIN
(
SELECT * FROM suppliers ORDER BY RAND() LIMIT 1
) s ON a.suplplier_id = s.suplplier_id
ORDER BY RAND()
This query first selects one supplier by random (eg, every supplier have the same chance) (oh but if there are suppliers without any advertisement, you should filter them out), then it gets only advertisements of this user (that is how this INNER JOIN works) and orders them by random

Complicated MySQL query?

I have two tables as follows:
I have a RatingsTable that contains a ratingname and a bit whether it is a positive or negative rating:
RatingsTable
----------------------
ratingname ispositive
----------------------
Good 1
Bad 0
Fun 1
Boring 0
And I have a FeedbackTable that contains feedback on things: the person rating, the rating and the thing rated. The feedback can be determined if it's a positive or negative rating based on the RatingsTable.
FeedbackTable
---------------------------------
username thing ratingname
---------------------------------
Jim Chicken Good
Jim Steak Bad
Ted Waterskiing Fun
Ted Hiking Fun
Nancy Hiking Boring
I am trying to write an efficient MySQL query for the following:
On a page, I want to display the the top 'things' that have the highest proportion of positive ratings. I want to be sure that the items from the feedback table are unique...meaning, that if Jim has rated Chicken Good 20 times...it should only be counted once. At some point I will want to require a minimum number of ratings (at least 10) to be counted for this page as well. I'll want to to do the same for highest proportional negative ratings, but I am sure I can tweak the one for positive accordingly.
To get the "things" in order of proportion of good ratings you can use this query:
SELECT thing, SUM(ispositive) / COUNT(*) AS proportion_positive
FROM (SELECT DISTINCT username, thing, ratingname FROM FeedbackTable) T1
JOIN RatingsTable T2
ON T1.ratingname = T2.ratingname
GROUP BY thing
ORDER BY proportion_positive DESC
For your example data it returns this:
thing proportion_positive
Chicken 1.0000
Waterskiing 1.0000
Hiking 0.5000
Steak 0.0000
To require at least 10 votes before displaying a thing in the results add this line after the GROUP BY:
HAVING COUNT(*) >= 10
To get the proportion of negative ratings change SUM(ispositive) to SUM(NOT ispositive).
Note: it might be better to add a unique constraint to your voting table instead of selecting only the disctinct values.
SELECT *
FROM `feedback`
LEFT JOIN `ratings` ON `feedback`.`rating` = `rating`.`label`
ORDER BY `rating`.`value` DESC
GROUP BY `feedback`.`username`
LIMIT 10
The summary: join the ratings to your feedback table, but group by the username so you only get one username per result.

Categories