Imagine this tables:
| USER |
|------|
| _id |
| PHOTO |
|-------|
| _id |
| user | - who uploaded it
| RATING |
|--------|
| user | - who vote
| photo | - for which foto
And then I need to extract All photos uploaded by $user And on top of that, what rating the photo has...
for example:
USER
1
PHOTO
50 | 1
51 | 1
52 | 1
RATING
2 | 50
3 | 51
2 | 51
2 | 52
4 | 51
3 | 50
My Expected result for function get_info($id):
$id = 1;
result:
_id | rating
50 | 2
51 | 3
52 | 1
Is there possible one task sql ? thanks
Use join and count with group by
select p._id,count(distinct r.user)
from photo p
join rating r on(p._id=r.photo)
where p.user = 1
group by p._id
Since your photo table has an association with rating table as _id is related to the photo column of rating table so join them, then count each distinct user for each photo
Demo
Related
I have a example table below. I am trying to create a SQL query that gets all user_ids besides user_id of the current user and then orders by number of matches to the row with the current user_id
For example, if the user has a user_id of '1', I want to get all of the user_ids corresponding with the rows of id 2-8, and then order the user_ids from most matches to the row of the current user to least matches with the row of the current user
Let's say var current_user = 1
Something like this:
SELECT user_id
FROM assets
WHERE user_id <> `current_user` and
ORDER BY most matches to `current_user`"
The output should get 7,8,3,9,2
I would appreciate anyone's input on how I can effectively achieve this.
Table assets
+----------+---------+-------+--------+-------+
| id | user_id | cars | houses | boats |
+----------+---------+-------+--------+-------+
| 1 | 1 | 3 | 2 | 3 |
| 2 | 8 | 3 | 2 | 5 |
| 3 | 3 | 3 | 2 | 2 |
| 4 | 2 | 5 | 1 | 5 |
| 5 | 9 | 5 | 7 | 3 |
| 8 | 7 | 3 | 2 | 3 |
+----------+---------+-------+--------+-------+
I think you can just do this:
select a.*
from assets a cross join
assets a1
where a1.user_id = 1 and a.user_id <> a1.user_id
order by ( (a.cars = a1.cars) + (a.houses = a1.houses) + (a.boats = a1.boats) ) desc;
In MySQL, a boolean expression is treated as an integer in a numeric context, with 1 for true and 0 for false.
If you want to be fancier, you could order by the total difference:
order by ( abs(a.cars - a1.cars) + abs(a.houses - a1.houses) + abs(a.boats - a1.boats) );
This is called Manhattan distance, and you would be implementing a version of a nearest neighbor model.
i have 2 tables (Titles and Episodes).
Table Titles
id | title | type | views
------------------------------
1 | Lucy | movie | 300
2 | Narcos | series | 2600
3 | Ip Man | movie | 120
4 | Creed | movie | 460
Table Episodes
id | title_id | title | episode | views
----------------------------------------------
1 | 2 | episode1 | 1 | 100
2 | 2 | episode2 | 2 | 260
3 | 2 | episode3 | 3 | 96
4 | 2 | episode4 | 4 | 210
Now i use this query to get most viewed episodes.
SELECT titles.id, titles.title, episodes.title_id, episodes.episode, episodes.views FROM titles, episodes WHERE titles.id = episodes.title_id ORDER BY episodes.views DESC LIMIT 0, 16
And i use this query for movies.
SELECT titles.id, titles.title, titles.views WHERE type = 'movie' ORDER BY titles.views DESC LIMIT 0, 16
I want to combine this two last queries into 1 temporary table to show most viewed movies and episodes.
Temporary Table
id | title_id | title | views
----------------------------------------------
1 | 4 | Creed | 460
2 | 1 | Lucy | 300
3 | 2 | Narcos Episode 2 | 260
4 | 2 | Narcos Episode 4 | 210
How can i do that ?
Thank you.
you can use view
see this page to more information
http://dev.mysql.com/doc/refman/5.7/en/create-view.html
I got it, thank you #sagi
(SELECT titles.id as title_id, concat(titles.title,' ',episodes.title) as
title,episodes.views as views
FROM titles, episodes
WHERE titles.id = episodes.title_id and type = 'series'
ORDER BY episodes.views DESC LIMIT 0, 16)
UNION ALL
(SELECT titles.id, titles.title, titles.views as views
FROM titles
WHERE type = 'movie'
ORDER BY titles.views DESC LIMIT 0, 16) ORDER BY views DESC
I have SQL (MySQL) that I've can't figure out. The application is using uploaded photos where there are many tagged participants in a photo and there is the possibility to give photos a vote between 1 to 5.
The original query gets all the votes for a photo and orders them by amount of votes and the average of those votes.
Now I need to limit the returned photos by the ones with more than 1 participant. So photos with only 1 participant should not be accounted for.
Simplified schema looks like this.
PHOTOS
----------------------
| id | title |
----------------------
| 1 | Fun stuff |
| 2 | Crazy girls |
| 3 | Single boy |
PHOTO_VOTES
-------------------------------------------
| photo_id | grade | date | user_id |
-------------------------------------------
| 1 | 3 | … | 12 |
| 1 | 3 | … | 12 |
| 2 | 5 | … | 14 |
| 2 | 4 | … | 14 |
| 3 | 4 | … | 15 |
| 3 | 4 | … | 18 |
PHOTO_PARTICIPANTS
-------------------------
| photo_id | user_id |
-------------------------
| 1 | 12 |
| 1 | 21 |
| 1 | 33 |
| 2 | 14 |
| 2 | 33 |
| 3 | 12 |
This is how far I got:
SELECT vote.photo_id,
COUNT(vote.photo_id) AS vote_count,
AVG(vote.grade) AS vote_average,
COUNT(pp.photo_id) AS participant_count
FROM photo_votes vote
LEFT JOIN photos p ON (vote.photo_id = p.id)
LEFT JOIN photo_participants pp ON (pp.photo_id = p.id)
GROUP BY vote.post_id,
HAVING vote_count >= 2
AND vote_average >= 3
AND participant_count > 1
ORDER BY count DESC, average DESC;
Basically what I'm looking for to end up with, excluding the photo with only one participant:
VOTES
-----------------------------------------------------------
| photo_id | vote_count | average | participant_count
-----------------------------------------------------------
| 1 | 2 | 3 | 3
| 2 | 2 | 4.5 | 2
Update
It turned out this is a very inefficient way of trying to do what I want. Gordons answer below did solve the problem, but as soon as I wanted to join fields from the photos table as well, the "cartesian product"-issue became a real problem - it became a very heavy and slow query.
The solution I finally ended up with is adding a cache-field into the photos table keeping track of how many participants are in the photo. In other words I added a 'participant_count' field to 'photos' that is being updated every time a change is made to the participants table. I also run a cron-job regularly to make sure all photos 'participant_count' are properly up-to-date.
First, you don't need left joins for this. But that shouldn't affect the results. The problem is that you have a cartesian product, because you have two 1-n relationships to photos: votes and participants.
The proper way to fix this is by using subqueries:
SELECT pv.photo_id, pv.vote_count, pv.vote_average, pp.participant_count
FROM (SELECT pv.photo_id, count(*) AS vote_count, avg(grade) AS vote_average
FROM photo_votes pv
GROUP BY pv.photo_id
) pv
JOIN
(SELECT pp.photo_id, count(*) AS participant_count
FROM photo_participants p;
GROUP bY pv.photo_id
) pp
ON pv.photo_id = pp.photo_id
WHERE pv.vote_count >= 2 AND
pv.vote_average >= 3 AND
pp.participant_count > 1
ORDER BY pv.vote_count DESC, pv.vote_average DESC;
Note that you don't even need the photos table, because you are not using any fields in it.
I have one report page which displays summarized data of other report.I have used php and mysqli. Let me explain you in deep.
I have a web application of store, where you can add product details. Using these product details you can generate packaging list report of products. And based on the generated packaging list report I need to generate one other report which contains summarized data of the packaging list.
below are my tables:
product table:
id | name | desc_id | purity | style_no | type | duty
1 | ABC | 1 | 18 | TEST123 | R | 100
2 | XYZ | 2 | 14 | TEST456 | B | 80
3 | DEF | 1 | 14 | TEST122 | R | 80
4 | PQR | 1 | 18 | TEST124 | R | 120
5 | HJK | 3 | 18 | TEST134 | B | 300
Description table:
id | descrip
1 | Gold Diamond Ring
2 | Gold Diamond Pendant
3 | Gold Diamond Earring
packaging_master table
id | name
1 | pkg_1
2 | pkg_2
packging_details table
id | pkg_id | prod_id
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 1 | 4
5 | 1 | 5
I have used below query to generate the packaging list report for specific id, which works correctly.
SELECT id, (SELECT descrip FROM description WHERE id = desc_id ) AS descrip,
style_no, type , purity, duty FROM product WHERE id IN ( SELECT prod_id FROM packaging_list_details WHERE pkg_id =1 ) ORDER BY descrip ASC , purity ASC
which displays below result:
id | descrip | style_no | type | purity | duty
1 |Gold Diamond Ring | TEST123 | R | 18 | 100
4 |Gold Diamond Ring | TEST124 | R | 18 | 120
3 |Gold Diamond Ring | TEST122 | R | 14 | 80
2 |Gold Diamond Pendant| TEST456 | B | 14 | 80
5 |Gold Diamond Earring| TEST134 | B | 18 | 300
Now I want summarized data of above result using query.
Like:
id | descrip | purity | qty | duty
1 |Gold Diamond Ring | 18 | 2 | 220
2 |Gold Diamond Ring | 14 | 1 | 80
3 |Gold Diamond Pendant| 14 | 1 | 80
4 |Gold Diamond Earring| 18 | 1 | 300
How can I achieve this?
You need to use the GROUP_BY statement - See MySql docs for more info.
This will translate the query to such
SELECT d.descrip, p.purity, count(p.purity) as qty, sum(p.duty)
FROM product p
INNER JOIN Description d ON p.desc_id = d.id
LEFT OUTER JOIN packaging_details pg on pg.prod_id = p.id
GROUP BY d.descrip, p.purity
ORDER BY d.descrip desc, p.purity desc
You can also use the sub select methodology you were using, but I prefer using joins. INNER JOIN will link both tables so that all their records are returned. OUTER JOIN will return all rows from the tables on the LEFT of the statement and matches them to values from the tables on the RIGHT.
See a full SQL Fiddle sample.
NOTE: I am not sure where you are getting the values for Id in your sample - Are they simply row numbers?
I think you should rewrite your query using JOINs:
SELECT
P.id
,D.descrip
,P.style_no
,P.type
,P.purity
,P.duty
FROM
packaging_list_details PLD
JOIN
product P ON
(P.id = PLD.prod_id)
LEFT JOIN
description D on
(D.desc_id = P.id)
WHERE
(PLID.pkg_id = 1)
That should give you the same result you already have. To get the totals, you can write a new query, similar to the above:
SELECT
P.id
,D.descrip
,P.type
,P.purity
,COUNT(p.id) as total_products
,SUM(P.duty) as total_duty
FROM
packaging_list_details PLD
JOIN
product P ON
(P.id = PLD.prod_id)
LEFT JOIN
description D on
(D.desc_id = P.id)
WHERE
(PLID.pkg_id = 1)
GROUP BY
P.id
,D.descrip
,P.type
,P.purity
The second query gives you the totals you are looking for.
I'm having trouble coming up with a query that returns the player's id, name along with the player's first match date, matchid and opponent.
I want the same information for player's last match as well.
`players`
id | name
1 | playername10
2 | playername22
3 | playername33
4 | playername45
5 | playername55
`matches`
id | gamedate | opponent
1 | 2011-01-01 | opponent1
2 | 2011-01-02 | opponent2
3 | 2011-01-03 | opponent3
4 | 2011-01-04 | opponent4
5 | 2011-01-05 | opponent5
`playermatchscores`
id | matchid | player | goals
1 | 1 | playername10 | 1
2 | 1 | playername22 | 2
3 | 2 | playername10 | 1
4 | 1 | playername33 | 1
5 | 3 | playername45 | 2
6 | 4 | playername55 | 1
7 | 2 | playername55 | 1
8 | 3 | playername22 | 2
9 | 5 | playername55 | 1
Where matchid is a foreign key to the id in table matches.
I tried several queries but I may be approaching it the the wrong way. How can I write a way to get the information I want?
Information about LEFT JOIN: http://www.w3schools.com/sql/sql_join_left.asp
SELECT players.id, MAX(matches.gamedate) AS first_match, MIN(matches.gamedate) AS last_match
FROM playermatchscores
LEFT JOIN players ON players.player = playermatchscores.player
LEFT JOIN matches ON matches.id = playermatchscores.matchid
GROUP BY players.player
I haven't tested this select.
P.S. You should use foreign key for players table too with player_id in playermatchscores.
After the changes in question:
SELECT players.*, matches.*,
FROM playermatchscores
LEFT JOIN players ON players.name = playermatchscores.player
LEFT JOIN matches ON matches.id = playermatchscores.matchid
ORDER BY matches.gamedate ASC
WHERE players.id = 3
LIMIT 1
For the last match replace ASC with DESC.
P.S. This is not the best way to do it but it should work.