So I have this data from basic mySQL select query, that outputs per row.
-Basic mySQL select query
ID---------DATE---------POINT1---POINT2------TOTAL
1----2013-01-03----------10----------16---------26
2----2013-01-03----------11----------22---------33
3----2013-01-03----------15----------7----------22
1----2013-01-04----------20----------4----------24
2----2013-01-04----------8-----------32---------40
3----2013-01-04----------16----------12---------28
1----2013-01-05----------12----------17---------29
2----2013-01-05----------2-----------29---------31
3----2013-01-05----------8-----------10---------18
What I want to do is sort the data by date in columns and by id in rows dynamically, something like per month. here is the desired output,
/----------/2013-01-03/---------/2013-01-04/------/2013-01-05/------/
ID--Point 1-Point2-Total-Point 1-Point2-Total-Point 1-Point2-Total
1----10-------16-----26-----20-------4-----24----12-----17------29
2----11-------22-----33------8------32-----40-----2-----29------31
3----15-------7------22-----16------12-----28-----8-----10------18
then output it to csv or excel. I'm kinda lost on how I can achieve this. If someone can guide me it would be great. thanks
You can unpivot the data in your columns and then perform a pivot to transform all of the data back into columns:
select id,
sum(case when date='2013-01-03' and col='Point1' then value end) Point1_01032013,
sum(case when date='2013-01-03' and col='Point2' then value end) Point2_01032013,
sum(case when date='2013-01-03' and col='Total' then value end) Total_01032013,
sum(case when date='2013-01-04' and col='Point1' then value end) Point1_01042013,
sum(case when date='2013-01-04' and col='Point2' then value end) Point2_01042013,
sum(case when date='2013-01-04' and col='Total' then value end) Total_01042013,
sum(case when date='2013-01-05' and col='Point1' then value end) Point1_01052013,
sum(case when date='2013-01-05' and col='Point2' then value end) Point2_01052013,
sum(case when date='2013-01-05' and col='Total' then value end) Total_01052013
from
(
select id, date_format(date, '%Y-%m-%d') date, 'Point1' col, Point1 as value
from yourtable
union all
select id, date_format(date, '%Y-%m-%d') date, 'Point2' col, Point2
from yourtable
union all
select id, date_format(date, '%Y-%m-%d') date, 'Total' col, Total
from yourtable
) src
group by id;
See SQL Fiddle with Demo
The result is:
| ID | POINT1_01032013 | POINT2_01032013 | TOTAL_01032013 | POINT1_01042013 | POINT2_01042013 | TOTAL_01042013 | POINT1_01052013 | POINT2_01052013 | TOTAL_01052013 |
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 1 | 10 | 16 | 26 | 20 | 4 | 24 | 12 | 17 | 29 |
| 2 | 11 | 22 | 33 | 8 | 32 | 40 | 2 | 29 | 31 |
| 3 | 15 | 7 | 22 | 16 | 12 | 28 | 8 | 10 | 18 |
Related
I have two different tables with the (almost) the same structure:
(not the best DB design, but unfortunately out of my control)
Table A:
+-----------+------+-------+-----+
| client_id | year | month | fee |
+-----------+------+-------+-----+
| 33 | 11 | 2022 | 11 |
| 42 | 11 | 2022 | 13 |
| 33 | 12 | 2022 | 27 |
| 16 | 12 | 2022 | 15 |
+-----------+------+-------+-----+
Table B:
+-----------+------+-------+-----+
| client_id | year | month | fee |
+-----------+------+-------+-----+
| 33 | 11 | 2022 | 19 |
| 57 | 11 | 2022 | 34 |
+-----------+------+-------+-----+
I want to SUM fees of all clients grouping bu month and year.
For one table the eloquent query is simple:
$queryA = DB::table('A')
->selectRaw('month, year, COUNT(*) AS total, SUM(fee) AS total_fee')
->groupBy(['month', 'year']);
($queryB will be the same, with ->table('B') instead ).
In order to get total sum of both tables, I want to use UNION.
The approach:
I want to apply a SELECT query on the result returned by UNION:
SELECT month, year, COUNT(*) AS total, SUM(total_fee) AS total_fee
FROM
(
(
SELECT month, year, COUNT(*) AS total, SUM(fee) AS total_fee
FROM A
GROUP BY month, year
) UNION (
SELECT month, year, COUNT(*) AS total, SUM(fee) AS total_fee
FROM B
GROUP BY month, year
)
) AS result_table
GROUP BY month, year
ORDER BY year DESC, month DESC;
The problem:
I tried this:
$queryA
->union($queryB)
->select(month, year, COUNT(*) AS total, SUM(total_fee) AS total_fee)
->groupBy(['month', 'year'])
the new SELECT statement is inserted into the $queryA sub-query.
Any idea how to achieve what I am looking for?
This question already has answers here:
How can I return pivot table output in MySQL?
(10 answers)
Closed 4 years ago.
Hai i have some sample data
bookId | bookPnr | bookDate | bookFullName | bookMobile | bookEmail | bookSource
9876543210 | BPT1100000000 | 2018-11-18 | User 1 | 9876543210 | test#gmail.com | Redbus
9876543211 | BPT1100000001 | 2017-11-18 | User 2 | 9876543211 | testOne#gmail.com | Redbus
9876543212 | BPT1100000002 | 2017-11-18 | User 3 | 9876543214 | testtwo#gmail.com | TicketGoose
I need a result like
Mobile | 2018 | 2017 | 2016 | Redbus | TicketGoose | total
9876543210 | 2 | 3 | 6 | 2 | 2 | 11
9876543211 | 1 | 1 | 1 | 2 | 1 | 3
So i need distinct mobile numbers based on year and source
I did query something like,
SELECT count(bookId), bookMobile, bookDate, bookSource FROM `booking_info`
GROUP by bookMobile, MONTH(bookDate), bookSource ORDER BY bookMobile DESC
Is it possible to do it with single query or we have to use PHP Any suggetions will be really appreciated.
You can use "conditional aggregates" to "pivot" your data. Basically this means placing a case expression inside an aggregation function. Here I have used COUNT():
SELECT
bookMobile
, count(case when year(bookDate) = 2016 then 1 end) as `2016`
, count(case when year(bookDate) = 2017 then 1 end) as `2017`
, count(case when year(bookDate) = 2018 then 1 end) as `2018`
, count(case when bookSource = 'Redbus' then 1 end) as Redbus
, count(case when bookSource = 'TicketGoose' then 1 end) as TicketGoose
FROM booking_info
GROUP BY
bookMobile
ORDER BY
bookMobile DESC
I'm trying to populate a table in HTML using a PHP script, which runs an SQL query which returns the following results (example):
UserID | Name | Month | Value |
1 | Joe | Jan | 123.00 |
1 | Joe | Feb | 22.00 |
1 | Joe | March | 32.50 |
21 | Derek | Jan | 45.76 |
21 | Derek | March | 12.31 |
But when I want to populate the table in PHP I want the table to look like this:
Name | January | February | March |
Joe | 123.00 | 22.00 | 32.50 |
Derek | 45.76 | | 12.31 |
But when generating the table using a PHP while loop its doing the following, which I would expect, as it's just looping through each fetched row:
Name | January | February | March |
Joe | 123.00 | | |
Joe | 22.00 | | |
Joe | 32.500 | | |
Derek | 45.76 | | | ... etc`
As I said, I would expect it to behave this way, but is there anyway to get it to display in the 2nd example.
I've already worked out some logic to place the values in the correct location, but it's still on a separate row, so at the moment it looks like this, which isn't ideal.
Name | January | February | March |
Joe | 123.00 | | |
Joe | | 22.00 | |
Joe | | | 32.50 |
Derek | 45.76 | | |
I hope I'm not missing anything obvious but I've had a look at several solutions within SQL but just can't seem to get it to work.
Any help would be appreciated.
EDITED:
Apologies, my SQL query is taking data from two different tables, as I am comparing values, so my understanding was that I couldn't use the GROUP BY statement. Here is my SQL query:
SELECT dbo_tstUser.UserID, dbo_tstUser.Name, dbo_tstUser.Month, dbo_tstUser.Value, dbo_tstUserImport.Value FROM dbo_tstUser INNER JOIN dbo_tstUserImport ON dbo_tstUser.UserID = dbo_tstUserImport.UserID;
You can use aggregation to do the pivoting:
select UserId, name,
max(case when Month = 'Jan' then value end) as January,
max(case when Month = 'Feb' then value end) as February,
max(case when Month = 'March' then value end) as March
from your_table
group by UserId, name;
If you don't want the UserId in the result, you can use:
select name,
max(case when Month = 'Jan' then value end) as January,
max(case when Month = 'Feb' then value end) as February,
max(case when Month = 'March' then value end) as March
from your_table
group by UserId, name;
Note that I kept the UserId in the group by clause to keep different people with same name separate.
You need to add a GROUP BY name statement to your SQL:-
SELECT UserID, Name, Month, Value
FROM table
GROUP BY Name
Edit:-
SELECT dbo_tstUser.UserID, dbo_tstUser.Name, dbo_tstUser.Month, dbo_tstUser.Value, dbo_tstUserImport.Value
FROM dbo_tstUser
INNER JOIN dbo_tstUserImport ON dbo_tstUser.UserID = dbo_tstUserImport.UserID
GROUP BY dbo_tstUser.UserID;
I have a problem with a query.
I have a table like this:
tbl_people
id | startDate | endDate | Gender
1 | 2010-03-01 | 2011-04-11 | m
2 | 2010-04-01 | 2010-06-14 | f
3 | 2010-03-01 | 2010-04-11 | m
4 | 2009-09-09 | 2009-10-10 | f
For all years given in the database I want to count the gender of the people, for who that year is between startDate and endDate. When startDate is 2010 and endDate 2011 it should count for both.
So the result should look like this:
year | m | f | m+f
2009 | 0 | 1 | 1
2010 | 2 | 1 | 3
2011 | 1 | 0 | 1
I have no really good idea how to realize that query for a list of all years.
Currently I have this:
select
sum(case tbl_people.Gender when 'm' then 1 else 0 end),
sum(case tbl_people.Gender when 'f' then 1 else 0 end),
count( tbl_people.Gender )
...
Best regards
You need to join with a table that contains all the years. You can either create a real table with all the years, or construct it on the fly in a subquery:
SELECT y.year,
SUM(p.Gender = 'm') AS m,
SUM(p.Gender = 'f') AS f,
COUNT(*) AS `m+f`
FROM (SELECT 2009 AS year
UNION
SELECT 2010 AS year
UNION
SELECT 2011 AS year) AS y
LEFT JOIN tbl_people AS p ON y.year BETWEEN YEAR(p.startDate) AND YEAR(p.endDate)
GROUP BY y.year
DEMO
For some reason this seems easy but I cannot figure it out. So I have a table called "contest_entries" and in it has columns "username" and "rating".
The table reads something like this:
Username | rating | Contest_id
John | 3 | 4
Mike | 1 | 4
Eric | 3 | 5
Mike | 1 | 6
John | 2 | 7
Mike | 1 | 8
John | 1 | 9
So for different contests people can place in different positions,
My question is how can I show how many contests a username has won, taken 2nd or 3rd (taking 1st place, aka rating=1, 2nd place being rating=2, 3rd place being rating=3) and listing all of the usernames as well, even if the username never took 1st, 2nd,3rd. And then finally rank them by who has the most wins (who has the most "rating=1").
So it would look like this:
Username | Ranking | 1st places | Second Places | Third Places
Mike | 1 | 3 | 0 | 0
John | 2 | 1 | 1 | 1
Eric | 3 | 0 | 0 | 1
etc etc.
SELECT x.username
, COUNT(CASE WHEN rating = 1 THEN 'foo' END) first
, COUNT(CASE WHEN rating = 2 THEN 'foo' END) second
, COUNT(CASE WHEN rating = 3 THEN 'foo' END) third
FROM ratings x
GROUP
BY username;
Try
SELECT username, #n := #n + 1 ranking, `1st places`, `2nd places`, `3rd places`
FROM
(
SELECT username,
SUM(CASE WHEN rating = 1 THEN 1 ELSE 0 END) `1st places`,
SUM(CASE WHEN rating = 2 THEN 1 ELSE 0 END) `2nd places`,
SUM(CASE WHEN rating = 3 THEN 1 ELSE 0 END) `3rd places`
FROM Table1
GROUP BY username
ORDER BY `1st places` DESC
) q, (SELECT #n := 0) n
Output:
| USERNAME | RANKING | 1ST PLACES | 2ND PLACES | 3RD PLACES |
-------------------------------------------------------------
| Mike | 1 | 3 | 0 | 0 |
| John | 2 | 1 | 1 | 1 |
| Eric | 3 | 0 | 0 | 1 |
Here is SQLFiddle demo