mysql query order by category top sales - mysql

Having trouble with how to do this query. There are three categories, ship,car, plane. I want to order category by most sales.
Here is the SQL fiddle http://sqlfiddle.com/#!2/e3344/1
Here is the table values
id | name | sales | category |
1 | mike | 2 | ship |
2 | john | 11 | car |
3 | david | 13 | ship |
4 | pablo | 24 | car |
5 | greg | 13 | car |
6 | nick | 1 | ship |
7 | anderson | 19 | ship |
8 | matt | 10 | plane |
9 | robbie | 3 | ship |
10 | victor | 1 | ship |
11 | ben | 11 | plane |
12 | rick | 6 | ship |
13 | christopher | 16 | car |
14 | steve | 8 | ship |
15 | claudio | 9 | plane |
How do i add up total sales by category and order DESC?

Try the group by and order by statement.
SELECT category, sum(sales)
FROM table
GROUP BY category
ORDER BY sum(sales) DESC
Edit
Just as a suggestion. Your "category" should be an extra entity in your database model.

Related

How to get only the second duplicated record in laravel 5.5?

Let's say i have a user table like this :
+----+-----------+----------------------+------+
| ID | Name | Email | Age |
+----+-----------+----------------------+------+
| 1 | John | john.doe1#mail.com | 24 |
| 2 | Josh | josh99#mail.com | 29 |
| 3 | Joseph | joseph410#mail.com | 21 |
| 4 | George | gge.48#mail.com | 28 |
| 5 | Joseph | jh.city89#mail.com | 24 |
| 6 | Kim | kimsd#mail.com | 32 |
| 7 | Bob | bob.s#mail.com | 38 |
| 8 | Joseph | psa.jos#mail.com | 34 |
| 9 | Joseph | joseph.la#mail.com | 28 |
| 10 | Jonathan | jonhan#mail.com | 22 |
+----+-----------+---------+------------+------+
In the actual, the database consists of more data and some of the data is duplicated, with more than two records. But the point is i want to get only the first and the second row of the duplicated rows that contains the name of "Joseph", How can i achieve this ? My code so far...
User::withTrashed()->groupBy('name')->havingRaw('count("name") >= 1')->get();
With that code the result will retrieve :
+----+-----------+----------------------+------+
| ID | Name | Email | Age |
+----+-----------+----------------------+------+
| 1 | John | john.doe1#mail.com | 24 |
| 2 | Josh | josh99#mail.com | 29 |
| 3 | Joseph | joseph410#mail.com | 21 |
| 4 | George | gge.48#mail.com | 28 |
| 6 | Kim | kimsd#mail.com | 32 |
| 7 | Bob | bob.s#mail.com | 38 |
| 10 | Jonathan | jonhan#mail.com | 22 |
+----+-----------+---------+------------+------+
And i use this code to try to get the second duplicated row :
User::withTrashed()->groupBy('name')->havingRaw('count("name") >= 2')->get();
The result is still same as the mentioned above :
+----+-----------+----------------------+------+
| ID | Name | Email | Age |
+----+-----------+----------------------+------+
| 1 | John | john.doe1#mail.com | 24 |
| 2 | Josh | josh99#mail.com | 29 |
| 3 | Joseph | joseph410#mail.com | 21 |
| 4 | George | gge.48#mail.com | 28 |
| 6 | Kim | kimsd#mail.com | 32 |
| 7 | Bob | bob.s#mail.com | 38 |
| 10 | Jonathan | jonhan#mail.com | 22 |
+----+-----------+---------+------------+------+
I want the result is to get record that have the id "5" with name "Joseph" like this :
+----+-----------+----------------------+------+
| ID | Name | Email | Age |
+----+-----------+----------------------+------+
| 1 | John | john.doe1#mail.com | 24 |
| 2 | Josh | josh99#mail.com | 29 |
| 4 | George | gge.48#mail.com | 28 |
| 5 | Joseph | jh.city89#mail.com | 24 |
| 6 | Kim | kimsd#mail.com | 32 |
| 7 | Bob | bob.s#mail.com | 38 |
| 10 | Jonathan | jonhan#mail.com | 22 |
+----+-----------+---------+------------+------+
But it seems only the first duplicate row is retrieved and i can't get the second duplicated row, can anybody give me suggestion ?
Let's start from your query
User::withTrashed()->groupBy('name')->havingRaw('count("name") >= 1')->get();
This will show all groups of rows whose count equals to 1 ore more. and this is the description of DISTINCT.
If you want to get only duplicate records you should get groups whose count is LARGER than 1.
The other thing to notice here is that a non-aggrigated column will be chosen randomly. because when you get a name and it's count, for example if you select name,count(name), email (email is not in the group by clause - not aggregated), and 4 rows have the same name. so you'll see:
+--------+-------------+-------+
| Name | Count(Name) | Email |
+--------+-------------+-------+
| Joseph | 4 | X |
+--------+-------------+-------+
what do you expect instead of X? which one of the 4 emails? actually, in SQLServer it's forbidden to select a non-aggrigated column and other databases will just give you a random one of the counted 3.
see this answer for more details it's explained very well: Do all columns in a SELECT list have to appear in a GROUP BY clause
So, we'll use having count(name) > 1 and select only the aggregated column name
DB::from('users')->select('name')->groupBy('name')->havingRaw('count("name") > 1')->get();
This should give you (didn't test it) this:
+--------+-------------+
| name | Count(name) |
+--------+-------------+
| Joseph | 4 |
+--------+-------------+
This will give you all names who have 2 or more instances. you can determine the number of duplicates in the having clause. for example having count(name) = 3 will give you all names which have exactly 3 duplicates.
So how to get the second duplicate? I have a question for that:
What is the first (original) duplicate? is it the one with the oldest created_at or the oldest updated_at ? or maybe some other condition?. because of that you should make another query with order by clause to give you the duplicates in the order most convenient to you. for example:
select * from `users` where `name` in (select `name` from users group by `name` having count(`name`) > 1) order by `id` asc
which will give:
+----+-----------+----------------------+------+
| ID | Name | Email | Age |
+----+-----------+----------------------+------+
| 3 | Joseph | joseph410#mail.com | 21 |
| 5 | Joseph | jh.city89#mail.com | 24 |
| 8 | Joseph | psa.jos#mail.com | 34 |
| 9 | Joseph | joseph.la#mail.com | 28 |
+----+-----------+---------+------------+------+

How to join three tables? Count, and Average SQL

I have three tables below with the following information
project.analytics
| proj_id | list_date | state
| 1 | 03/05/10 | CA
| 2 | 04/05/10 | WA
| 3 | 03/05/10 | WA
| 4 | 04/05/10 | CA
| 5 | 03/05/10 | WA
| 6 | 04/05/10 | CA
employees.analytics
| employee_id | proj_id | worked_date
| 20 | 1 | 3/12/10
| 30 | 1 | 3/11/10
| 40 | 2 | 4/15/10
| 50 | 3 | 3/16/10
| 60 | 3 | 3/17/10
| 70 | 4 | 4/18/10
email.forward
| email_id | event_id | employee_id
| 1 | 1 | 20
| 2 | 2 | 80
| 3 | 3 | 40
| 4 | 4 | 50
| 5 | 5 | 50
| 6 | 6 | 60
How can I determine which emails (email_id) drove employees to work on projects(amount) by month and state?
Desired output:
Email_id | Month | state |# of employee
1 | March | CA | 1
1 | April | WA | 2
2 | July | WA | 2
2 | August | CA | 1
I'm pretty stuck as I'm not sure how to maneuver the three tables together.
Essentially I want to be able to answer
This email_id had this many employees work on this project on this month and state.
Something like this should work:
SELECT c.email_id, month(b.worked_date), a.state, count(distinct b.employee_id)
FROM project.analytics a
JOIN employees.analytics b
ON a.project_id = b.project_id
JOIN email.forward c
on c.employee_id = b.employee_id
GROUP BY c.email_id, month(b.worked_date)
I am not sure what DBMS you use, so MONTH() may or may not exist there, but you should be able to find a similar function.

MySQL grouping and summing

I have a query that returns a table that looks something like this:
+------+----------+-------+------+----+
| pID | name | month | q | s |
+------+----------+-------+------+----+
| 1468 | bob | 2 | 1 | 14 |
| 1469 | bob | 2 | 1 | 2 |
| 1470 | bob | 2 | 1 | 9 |
| 1468 | bob | 3 | 1 | 7 |
| 1469 | bob | 3 | 1 | 8 |
| 1470 | bob | 3 | 1 | 11 |
+------+----------+-------+------+----+
and I would like the output to be
+----------+-------+------+-----+
| name | month | q | sub |
+----------+-------+------+-----+
| bob | 2 | 1 | 25 |
| bob | 3 | 1 | 26 |
+----------+-------+------+-----+
Essentially, I want the first two columns of my output to be name, month and q grouped by name and month (they will always have the same data per line in this grouping) and I want the last column to be the SUM of s grouped by name only.
Thanks.
It should be something like this:
SELECT name, month, q, SUM(sub)
FROM table
GROUP BY name, month, q

Querying a many to many relationship in SQL

I have the following SQL relationship
user has many games
games has may users
User
----
id | name | age |
__________________
1 | mike | 11 |
2 | jeff | 12 |
3 | jake | 31 |
4 | lemd | 81 |
Game
-----
id | name | time |
_____________________
1 | froyo | 11:10 |
2 | honey | 12:22 |
3 | combb | 13:00 |
4 | lolli | 14:00 |
User_Game
----------
| userid | game_id |
___________________
| 1 | 2 |
| 2 | 2 |
| 3 | 1 |
| 4 | 3 |
| 1 | 2 |
| 2 | 4 |
| 2 | 1 |
For each of the users is there a way to get a
list of games that they have played including the number
of games that each user participated in.
Edit
I tried this query
Select User.name, User.age
from User
inner join User_Game
on User.id=User_Game.userid;
However not sure how I could add the count to it
SELECT
userid,
GROUP_CONCAT(game_id) as game_list,
COUNT(*) as total_games
FROM
USER_GAME
GROUP BY
userid;

Sum Team Competition Values with SQL

Overview
I have a bunch of data on a competition I'm holding and I want to present it in a better format.
There's 4 tables; the first two are self-explanatory, the points and extras table are essentially the exact same thing, they're just stored in different tables with slightly different column names.
Data
users
+----+---------------+------+
| id | name | team |
+----+---------------+------+
| 1 | John Doe | 1 |
| 2 | Jane Lane | 1 |
| 3 | Jack Black | 4 |
| 4 | Dan Bam | 3 |
| 5 | Pam Jan | 2 |
| 6 | Pop Tart | 2 |
| 7 | John Q | 1 |
| 8 | Hugo Strange | 3 |
| 9 | Jimmy Neutron | 2 |
+----+---------------+------+
teams
+----+-----------------+
| id | name |
+----+-----------------+
| 1 | Team Fun |
| 2 | The Dream Team |
| 3 | In It To Win It |
| 4 | Buddies |
+----+-----------------+
points
+---------+--------+------------+
| user_id | points | event |
+---------+--------+------------+
| 1 | 2 | Basketball |
| 2 | 4 | Basketball |
| 5 | 1 | Basketball |
| 8 | 3 | Basketball |
| 9 | 5 | Basketball |
| 2 | 8 | Volleyball |
| 5 | 5.5 | Volleyball |
| 6 | 6.5 | Volleyball |
| 7 | 2 | Volleyball |
| 8 | 4 | Volleyball |
| 9 | 9.5 | Volleyball |
| 1 | 2.5 | Dodgeball |
| 3 | 3 | Dodgeball |
| 4 | 4 | Dodgeball |
| 6 | 9 | Dodgeball |
| 7 | 2.5 | Dodgeball |
| 9 | 3 | Dodgeball |
+---------+--------+------------+
extras
+---------+--------+---------------------+
| user_id | points | description |
+---------+--------+---------------------+
| 1 | 5 | Great Sportsmanship |
| 3 | 10 | Team Player |
| 8 | 5.5 | Most Improved |
+---------+--------+---------------------+
What I'm Trying To Do
I want to write a query to return all the events (and "extras") a specific team participated in, the total points from all members of the team, and the participating members in that event.
Example below uses Team Fun (Team 1):
+---------------------+--------+--------------------+------------+
| event | points | members | members_id |
+---------------------+--------+--------------------+------------+
| Basketball | 6 | John Doe,Jane Lane | 1,2 |
| Volleyball | 10 | Jane Lane,John Q | 2,7 |
| Dodgeball | 5 | John Doe,John Q | 1,7 |
| Great Sportsmanship | 5 | John Doe | 1 |
+---------------------+--------+--------------------+------------+
If anyone could help me with figuring this out, I'd appreciate it!
SQLFiddle
This is a SQLFiddle with the data schema above - http://sqlfiddle.com/#!2/e8f97a
You can use a UNION to get the extras and points together:
SELECT user_id, points, event
FROM points
UNION ALL
SELECT user_id, points, description AS event
FROM extras
Then using this, you can compile your info with a SUM and a couple of GROUP_CONCATs:
SELECT P.event, SUM(P.points) AS points,
GROUP_CONCAT(U.name) AS members, GROUP_CONCAT(U.id) AS members_id
FROM teams T
INNER JOIN users U ON T.id = U.team
INNER JOIN
(
SELECT user_id, points, event
FROM points
UNION ALL
SELECT user_id, points, description AS event
FROM extras
) P ON U.id = P.user_id
WHERE T.id = #teamId
GROUP BY P.event
SQL Fiddle Example