I have a simple table which holds the date and the total sales made for a certain group:
date | totalsales
=======================
2014-05-01 | 3000
2014-05-02 | 3100
2014-05-03 | 3500
2014-05-04 | 3650
I like to calculate some things like:
sales per day
average sales
growth in %
Result should look like (calculate by hand so maybe wrong :) )
date | sales | average | growth
=======================================
2014-05-01 | 0 | 0 | 0
2014-05-02 | 100 | 50 | 100
2014-05-03 | 400 | 166.66 | 400
2014-05-04 | 150 | 162.5 | 37.5
Is this even possible in a sql statement or should I calculate with PHP or another server software?
Assuming each date gets its own unique row, you could do it by joining back to your original table like so:
SELECT t1.Date, CASE WHEN t2.Date IS NULL THEN 0 ELSE (t1.totalsales - t2.totalsales)
END AS sales
FROM table t1
LEFT JOIN table t2 ON t2.Date = DATE_ADD(t1.Date, INTERVAL -1 DAY)
ORDER BY 1
This will give you at least your first column, and you should be able to figure out the math for the rest from there. It's important to use a left join with the CASE statement here because otherwise you won't get the lowest date in your table (your first row)
If each date does not get its own unique row, this is method is still viable, you just need to create your datasets in a subquery using GROUP BY and SUM on the date column.
Here is the full query with no subselect at each row : (Thanks to #nmarsh for writting the hardest part)
See SQL fiddle : http://sqlfiddle.com/#!2/be4654/34/0
SELECT
t1.Date,
CASE
WHEN t2.date IS NULL THEN 0 ELSE (t1.totalSales - t2.totalSales)
END AS sales,
CASE
WHEN t2.date IS NULL THEN 0 / (#curRow := #curRow + 1) ELSE ((#curSum := #curSum + (t1.totalSales - t2.totalSales)) / (#curRow := #curRow + 1))
END AS average,
CASE
WHEN t3.date IS NULL AND t2.date IS NULL THEN 0
WHEN t3.date IS NULL THEN (t1.totalSales - t2.totalSales)
WHEN t2.date IS NULL THEN 0 ELSE ((t1.totalSales - t2.totalSales) * 100) / (t2.totalSales - t3.totalSales)
END AS growth
FROM test t1
LEFT JOIN test t2 ON t2.date = DATE_ADD(t1.Date, INTERVAL -1 DAY)
LEFT JOIN test t3 ON t3.date = DATE_ADD(t2.Date, INTERVAL -1 DAY)
JOIN (SELECT #curRow := 0) r
JOIN (SELECT #curSum := 0) ct
ORDER BY 1;
Original table :
date | totalsales
=======================
2014-05-01 | 3000
2014-05-02 | 3100
2014-05-03 | 3500
2014-05-04 | 3650
OUTPUT
date | sales | average | growth
=======================================
2014-05-01 | 0 | 0 | 0
2014-05-02 | 100 | 50 | 100
2014-05-03 | 400 | 166.66 | 400
2014-05-04 | 150 | 162.5 | 37.5
You can use recursive statement. In each iteration, calculate the requested data for one day, and drop the first (oldest) day.
You can also do it with PHP, which seems better because you don't want to put too much load on the MySQL tables in case it does not saves you time/calculations.
Not too sure about the numbers, but if you are more specific about the results I can double check.
You can use ROW_NUMBER() to create 2 data sets and join them on ROW_NUMBER() and ROW_NUMBER()-1 to get an offset to current and previous values to calculate the growth. Sample :
DECLARE #Data TABLE (SalesDate DATETIME, totalSales INT)
INSERT INTO #Data (SalesDate , totalSales) VALUES ('2014-05-01' , 3000)
INSERT INTO #Data (SalesDate , totalSales) VALUES ('2014-05-02' , 3100)
INSERT INTO #Data (SalesDate , totalSales) VALUES ('2014-05-03' , 3500)
INSERT INTO #Data (SalesDate , totalSales) VALUES ('2014-05-04' , 3650)
SELECT
CurrentDt.SalesDate
,ISNULL(CurrentDt.totalSales - PreviousDt.totalSales ,0) AS Sales
,FirstDate.FirstDate
, NULLIF(CAST((CurrentDt.SalesDate - FirstDate.FirstDate) AS INT)+1,0) AS SellingDays
,(ISNULL(CurrentDt.totalSales - PreviousDt.totalSales ,0))
/ NULLIF(CAST((CurrentDt.SalesDate - FirstDate.FirstDate) AS INT)+1,0) AS AverageSales
FROM
(SELECT Min(SalesDate) AS FirstDate FROM #Data) AS FirstDate,
/*Base Sales Data*/
(
SELECT
ROW_NUMBER() OVER(ORDER BY SalesDate) AS RowNum
,SalesDate
,totalSales
FROM
#Data
) AS CurrentDt
/*Previous Value for Growth*/
LEFT JOIN
(
SELECT
ROW_NUMBER() OVER(ORDER BY SalesDate) AS RowNum
,SalesDate
,totalSales
FROM
#Data
) AS PreviousDt
ON CurrentDt.RowNum -1 = PreviousDt.RowNum
I have used MSSQL, but MySQL supports ROW_NUMBER OVER.
I hope this query help you
SELECT
sample.id,
sample.date AS oggi,
sample.value AS sales,
((SELECT SUM(sample.value) FROM sample WHERE sample.date <= oggi ) / (SELECT COUNT(sample.value) FROM sample WHERE sample.date <= oggi ) ) AS avarege,
sample.value / IF((SELECT sample.value FROM sample WHERE sample.date = (oggi - INTERVAL 1 DAY )) = 0,sample.value,(SELECT sample.value FROM sample WHERE sample.date = (oggi - INTERVAL 1 DAY ))) *100 AS 'growt-percent'
-- (SELECT SUM(sample.value) FROM sample WHERE sample.date <= oggi ) AS somma,
-- (SELECT count(sample.value) FROM sample WHERE sample.date <= oggi ) AS conta,
-- (SELECT sample.value FROM sample WHERE sample.date = (oggi - INTERVAL 1 DAY )) as valoreieri,
FROM sample
WHERE sample.date BETWEEN '2014-05-01 00:00:00' AND '2014-05-31 00:00:00'
table data is
id date value
1 2014-05-01 00:00:00 0
2 2014-05-02 00:00:00 100
3 2014-05-03 00:00:00 400
4 2014-05-04 00:00:00 150
5 2014-05-05 00:00:00 200
result is
id oggi sales avarege growt-percent
1 2014-05-01 00:00:00 0 0.0000 (NULL)
2 2014-05-02 00:00:00 100 50.0000 100.0000
3 2014-05-03 00:00:00 400 166.6667 400.0000
4 2014-05-04 00:00:00 150 162.5000 37.5000
5 2014-05-05 00:00:00 200 170.0000 133.3333
note that i use datetime field not only date
if you have question about query ask
sorry for my bad english
edit
the last 3 rows are commented because i used it only for test
Related
This is sample data in my table
id_item | qty | t_in | t_out | created_at
1 5 1 0 2018-07-05 10:41:00
1 5 1 0 2018-08-03 10:41:00
1 5 0 1 2018-08-05 10:41:00
1 5 1 0 2018-09-05 10:41:00
1 5 1 0 2018-09-20 10:41:00
1 5 0 1 2018-10-31 10:41:00
My expected result will be
id_item | qty | year | month
1 5 2018 07
1 5 2018 08
1 15 2018 09
1 10 2018 10
What i have tried it works, but not desired output when want to group by montly
$date = '2018-10-31'
$test = Model::whereDate('created_at','<=',$date)->select(DB::raw('(SUM(CASE T_IN WHEN 1 THEN qty ELSE qty * - 1 END)) as total'))->groupBy('id_item')->get();
Raw queries to get the quantity for one month
Select id_item,
(SUM(CASE T_IN WHEN 1 THEN qty ELSE qty * - 1 END)) as total
from transactions
where DATE(created_at) <= 2018-10-31
group by id_item
Worst case
$last_day_of_month = [//list of last day of each month]
//then using loop to get qty of each month refer to the raw queries above
From the query above, i only able to get one line of record. I also tried to group by month and year but incorrect result caused of the date condition. How can i include multiple <= $date condition and group it accordingly to get desired output?
Any idea or is that possible to make it? Thanks.
It is a Rolling Sum problem. In newer versions of Mariadb/MySQL, it can be solved using Window Functions with Frames. However, you don't have that available.
We can rather solve this using user-defined variables. In a Derived table, we first determine the total change in qty for a month. Then, we use this result-set to calculate "final qty" at the end of a month, by adding up the previous month (row)'s qty with current month (row)'s qty_change.
I have also extended the query to consider the cases when there are more than one id_item values.
Try the following Raw query:
SELECT
#roll_qty := CASE WHEN #id_itm = dt.id_item
THEN #roll_qty + dt.qty_change
ELSE dt.qty_change
END AS qty,
#id_itm := dt.id_item AS id_item,
dt.year,
dt.month
FROM
(
SELECT
t.id_item,
SUM(t.qty * t.t_in - t.qty * t.t_out) AS qty_change,
YEAR(t.created_at) AS `year`,
LPAD(MONTH(t.created_at), 2, '0') AS `month`
FROM your_table AS t
GROUP BY t.id_item, `year`, `month`
ORDER BY t.id_item, `year`, `month`
) AS dt
CROSS JOIN (SELECT #roll_qty := 0,
#id_itm := 0
) AS user_init_vars;
| id_item | year | month | qty |
| ------- | ---- | ----- | --- |
| 1 | 2018 | 07 | 5 |
| 1 | 2018 | 08 | 5 |
| 1 | 2018 | 09 | 15 |
| 1 | 2018 | 10 | 10 |
View on DB Fiddle
If you are going to use variables, you need to do it correctly. MySQL does not guarantee the order of evaluation of expressions in a SELECT. So, a variable should not be assigned in one expression and then used in another.
This makes for complicated expressions, but it is possible:
select yyyy, mm, total,
(#t := if(#ym = concat_ws('-', yyyy, mm), #t + total,
#ym := concat_ws('-', yyyy, mm), total
)
) as running_total
from (select year(created_at) as yyyy, month(created_at) as mm,
id_item,
sum(case T_IN when 1 then qty else - qty end) as total
from transactions
where created_at < '2018-11-01'
group by id_item
order by id_item, min(created_at)
) i cross join
(select #ym := '', #n := 0);
I need to find the period without pause in days since last pause.
I have a next table:
id | user | date
-----------------------
1 | 1 | 16.02.2017
1 | 1 | 15.02.2017
1 | 1 | 14.02.2017
1 | 1 | 13.02.2017
1 | 1 | 10.02.2017
Last pause: 10-13 February
Last period without pause: 4 days
I tried to found the difference between day like in this question, but as result it was always NULL. And this is only first part. For second part I thought to use something like ranking, but don't know if it will work.
I plan to use it with PHP 7 + MySQL 5.6.
I've used this sample:
create table if not exists myt(id int, dd date);
insert into myt values
(1, '2017-01-01'),
(1, '2017-01-02'),
(1, '2017-01-03'),
(1, '2017-01-04'),
(1, '2017-01-08'),
(1, '2017-01-09'),
(1, '2017-01-10');
First you should set a partition by consecutive days:
select id, dd,
if(#last_date = '1900-01-01' or datediff(dd, #last_date) = -1, #cn := #cn, #cn := +1) consecutive,
#last_date := dd
from
(select #last_date := '1900-01-01', #cn := 0) x,
(select id, dd
from myt
order by dd desc) y
;
This returns:
+----+---------------------+-------------+
| id | dd | consecutive |
+----+---------------------+-------------+
| 1 | 10.01.2017 00:00:00 | 0 |
| 1 | 09.01.2017 00:00:00 | 0 |
| 1 | 08.01.2017 00:00:00 | 0 |
+----+---------------------+-------------+
| 1 | 04.01.2017 00:00:00 | 1 |
| 1 | 03.01.2017 00:00:00 | 1 |
| 1 | 02.01.2017 00:00:00 | 1 |
| 1 | 01.01.2017 00:00:00 | 1 |
+----+---------------------+-------------+
After you set a partition, then get MAX and MIN date for each partition:
select id, min(dd) as ini, max(dd) as fin, datediff(max(dd), min(dd)) as Days
from (
select id, dd,
if(#last_date = '1900-01-01' or datediff(dd, #last_date) = -1, #cn := #cn, #cn := +1) consecutive,
#last_date := dd
from
(select #last_date := '1900-01-01', #cn := 0) x,
(select id, dd
from myt
order by dd desc) y
) z
group by consecutive
;
Result:
+----+---------------------+---------------------+------+
| id | ini | fin | Days |
+----+---------------------+---------------------+------+
| 1 | 08.01.2017 00:00:00 | 10.01.2017 00:00:00 | 2 |
+----+---------------------+---------------------+------+
| 1 | 01.01.2017 00:00:00 | 04.01.2017 00:00:00 | 3 |
+----+---------------------+---------------------+------+
Check it: http://rextester.com/XMIX80360
Try this query. It will find all pauses -
SELECT curr_date, prev_date FROM (
SELECT t1.date curr_date, MAX(t2.date) prev_date FROM periods t1
LEFT JOIN periods t2
ON t1.date > t2.date
GROUP BY t1.date) t
WHERE DATEDIFF(curr_date, prev_date) > 1
The result is:
13-Feb-17 10-Feb-17
Then add condition/LIMIT to get only one row.
I am trying to write general query like,
select count(distinct t1.`date`) from period t1 left join period t2 ON t2.user = t1.user and t1.`date` - INTERVAL 1 DAY = t2.date where t2.id is null
Can you try this query once,
it should work, I have used it in my almost same case.
This query will return the latest hole:
select
m.`date`,
min(m1.`date`) as next_date,
datediff(min(m1.`date`), m.`date`)+1 as diff
from
mytable m left join mytable m1
on m.`date`<m1.`date`
group by
m.`date`
having
datediff(min(m1.`date`), m.`date`)>1
order by
m.`date` desc
limit 1
The following query:
SELECT MIN(`date`) AS date_start,
MAX(`date`) AS date_end,
MAX(days_diff) AS pause_days,
COUNT(*) + 1 AS period_without_pays
FROM (
SELECT id, user, `date`,
DATE_SUB(`date`, INTERVAL rn DAY) AS group_date,
DATEDIFF(`date`, COALESCE(prevDate, `date`)) AS days_diff
FROM (
SELECT t1.id, t1.user, t1.`date`,
#rn := #rn + 1 AS rn,
(SELECT t2.`date`
FROM mytable AS t2
WHERE t1.id = t2.id AND t1.user = t2.user AND t1.`date` > t2.`date`
ORDER BY `date` DESC LIMIT 1) AS prevDate
FROM mytable AS t1
CROSS JOIN (SELECT #rn := 0) AS v
ORDER BY `date`) AS t) AS x
GROUP BY id, user, group_date, days_diff
HAVING SUM(days_diff) > 0
returns:
date_start date_end pause_days period_without_pays
-----------------------------------------------------
2017-02-14 2017-02-16 1 4
2017-02-13 2017-02-13 3 2
The row with pause_days > 1 returns the start date of the pause along with the number of days.
The row with pause_days = 1 returns the start / end dates of an island of consecutive records having consecutive dates along with the count of these dates.
Note: The above query works with the sample data provided. You may have to tweak the query a little bit so as to adjust it to the complexity of the actual data.
Try this one:
SET #dateDiff=NULL;SET #dateDiff2='';
SELECT diff.secondDate AS fromDate,diff.initialDate AS toDate, diff.dateDiffR FROM (
SELECT d.date AS initialDate,#dateDiff AS secondDate,IF(#dateDiff IS NULL,#dateDiff:=d.date,0) AS try,
IF(DATE(#dateDiff)!=DATE(d.date),DATEDIFF(d.date,#dateDiff),NULL) AS dateDiffR,
IF(#dateDiff!=#dateDiff2,#dateDiff2:=#dateDiff,0) AS try1,
IF(DATE(#dateDiff)!=DATE(d.date),#dateDiff:=d.date,NULL) AS assign FROM
(SELECT b.date FROM mytable b)d ) diff WHERE diff.dateDiffR>0
it will give you the date difference with its date range. If you get negative count then swap the dates on parameters' for DATEDIFF;
(Posted on behalf of the OP).
I adapted little bit query from #McNets:
select user, min(dd) as ini, max(dd) as fin, datediff(max(dd), min(dd))+1 as Days, consecutive
from (
select user,dd,
if(#last_date = curdate() or datediff(dd, #last_date) >= -1, #cn := #cn, #cn := #cn+1) consecutive,
#last_date := dd
from
(select #last_date := curdate(), #cn := 0) x,
(select user, date as dd
from myt
where user = %id
order by dd desc) y
) z
group by consecutive
order by CAST(consecutive AS UNSIGNED)
I added filter by user, changed cause to '>= -1' to accept time usage, added number of the serie and changed initial date from '1900-01-01' to CURDATE() function (i don't see any influence to query result from this action).
Now using number of the series can find the longest series and its dates.
I have two tables with given structure :
Table 1:
ST_Id ST_Name
1 xx
2 yy
Table 2 :
AT_Id AT_Amt ST_ID Date
1 500 1 2015-11-17
2 1000 1 2015-11-15
3 300 1 2015-12-1
4 200 2 2015-11-2
I want to get results from mysql order by month. In my php page, I have a table structure for displaying data like shown below
State December November September
xx 300 1500 0
yy 0 200 0
Along with these months, I have a sorting link for sorting the amounts based on month. So when I click the sorting image corresponding to the month November, it should list the table data according to the order of amount in that column. If I clicked for ascending sorting it should list like,
State December November September
yy 0 200 0
xx 300 1500 0
I tried with following query :
SELECT ST.ST_Name,SUM(AT.AT_Amt)
FROM `Table2` AS AT
LEFT JOIN Table1 AS ST ON AT.ST_Id = ST.ST_Id
WHERE AT.Date BETWEEN '2015-04-01' AND '2015-12-31' GROUP BY MONTH( AT.Date) ORDER BY IF(MONTH(AT.Date) = 11 , SUM(AT.AT_Amt) , MONTH( AT.Date)) ASC
This query is returning data like shown below.
ST_Name SUM(AT.AT_Amt)
xx 300
xx 1700
But the expected result is :
ST_Name SUM(AT.AT_Amt)
yy 200
xx 1500
Can anyone please help me fix this? Thanks in advance.
You can do something like this:
SELECT
st_name,
SUM(CASE WHEN MONTH(dt) = 12 THEN at_amt ELSE 0 END) AS December,
SUM(CASE WHEN MONTH(dt) = 11 THEN at_amt ELSE 0 END) AS November,
SUM(CASE WHEN MONTH(dt) = 10 THEN at_amt ELSE 0 END) AS September
FROM table2
INNER JOIN table1 ON table1.st_id = table2.st_id
GROUP BY st_name;
Once you get data into PHP, you could just use JavaScript to do client-side sorting using TableSorter or similar library. That way sorting doesn't incur the expense of re-querying the database.
Result of your data will be:
+---------+----------+----------+-----------+
| st_name | December | November | September |
+---------+----------+----------+-----------+
| xx | 300 | 1500 | 0 |
| yy | 0 | 200 | 0 |
+---------+----------+----------+-----------+
Click the link below for a running demo:
SQLFiddle
EDIT:
Based on your comment, is this something you need?
SELECT
ST.ST_Name,
SUM(AT.AT_Amt) as Amount
FROM `Table2` AS AT
LEFT JOIN Table1 AS ST ON AT.ST_Id = ST.ST_Id
WHERE AT.dt BETWEEN '2015-04-01' AND '2015-12-31'
AND MONTH(AT.dt) = 11
GROUP BY ST.ST_Name
ORDER BY Amount
Example: http://sqlfiddle.com/#!9/51c7c/7 for demo
Result:
| st_name | Amount |
|---------|--------|
| yy | 200 |
| xx | 1500 |
I want to compute some stats (with a MySQL backend) sorted by date and with dynamic intervals (week, month, year).
Here is a little example :
Mysql table :
tracker_click
| ID | SITE_ID | CREATED_AT |
| ---- |---------| --------------------|
| 153 | 2 | 2013-07-22 15:43:25 |
| 154 | 2 | 2013-07-25 16:45:46 |
| 2501 | 2 | 2013-09-15 17:45:48 |
I want to get the total click number by SITE_ID by week for the last month with one query
And the same thing by month for the last year.
An example of what I want by week for the last month is :
| click number | SITE_ID | BEGIN_DATE | END_DATE |
|----------------|---------|----------------------|---------------------|
| 25 | 2 | 2013-07-01 00:00:00 | 2013-07-08 00:00:00 |
| 19 | 2 | 2013-08-09 00:00:00 | 2013-08-16 00:00:00 |
| 53 | 2 | 2013-0717- 00:00:00 | 2013-08-24 00:00:00 |
I don’t know if there is a solution to get exaclty this array with only one query without any other processes.
Thank you
This should get you the counts for the last month (ie, last 4 weeks), including weeks where the count is 0 for each site id. If you have a table of sites to get the site id from it means the cross join to the sub query can be replaced with a simple cross join to a table.
This generates a range of numbers from 0 to 5 and subtracts that number of weeks from the current date, formats that to give the Sunday and Saturday of the resulting week and checks that the resuling week is a week between the current date and the current date minus 1 month (done this way rather that just subtracting 4 weeks to cope with variable length months).
SELECT Weeks.aWeek_start, Weeks.aWeek_end, all_site_id.site_id, COUNT(tracker_click.id)
FROM
(
SELECT STR_TO_DATE(DATE_FORMAT(DATE_SUB(NOW(), INTERVAL units.i WEEK), '%Y%U Sunday 00:00:00'), '%X%V %W %H:%i:%s') AS aWeek_start,
STR_TO_DATE(DATE_FORMAT(DATE_SUB(NOW(), INTERVAL units.i WEEK), '%Y%U Saturday 23:59:59'), '%X%V %W %H:%i:%s') AS aWeek_end
FROM (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5)units
WHERE DATE_FORMAT(DATE_SUB(NOW(), INTERVAL units.i WEEK), '%Y%U') BETWEEN DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 1 MONTH), '%Y%U') AND DATE_FORMAT(NOW(), '%Y%U')
) Weeks
CROSS JOIN
(
SELECT DISTINCT site_id
FROM tracker_click
) AS all_site_id
LEFT OUTER JOIN tracker_click
ON tracker_click.CREATED_AT BETWEEN Weeks.aWeek_start AND Weeks.aWeek_end
AND tracker_click.site_id = all_site_id.site_id
GROUP BY Weeks.aWeek_start, Weeks.aWeek_end, all_site_id.site_id
A similar query could be done for months of the year
SELECT Months.aMonth_start, Months.aMonth_end, all_site_id.site_id, COUNT(tracker_click.id)
FROM
(
SELECT DATE_FORMAT(DATE_SUB(NOW(), INTERVAL units.i MONTH), '%Y/%m/01 00:00:00') AS aMonth_start,
DATE_FORMAT(LAST_DAY(DATE_SUB(NOW(), INTERVAL units.i MONTH)), '%Y/%m/%d 23:59:59') AS aMonth_end
FROM (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10 UNION SELECT 11)units
) Months
CROSS JOIN
(
SELECT DISTINCT site_id
FROM tracker_click
) AS all_site_id
LEFT OUTER JOIN tracker_click
ON tracker_click.CREATED_AT BETWEEN Months.aMonth_start AND Months.aMonth_end
AND tracker_click.site_id = all_site_id.site_id
GROUP BY Months.aMonth_start, Months.aMonth_end, all_site_id.site_id
SELECT count(*), site_id, extract(WEEK from created_at) as start_date,
date_add(extract(WEEK from created_at), 1, week) as end_date
FROM click_tracker
GROUP BY site_id, extract(WEEK from created_at)
and you can add where clause to filter results additionally.
My Db design is :
Tbl_id booked_by date
1 W 2014-02-01
2 P 2014-02-01
3 P 2014-02-01
4 P 2014-02-01
5 W 2014-02-04
6 W 2014-02-04
7 P 2014-02-04
I want to display counting of W , P Where given Date and Grouped by Date and with Using php mysql ..
like
I NEED OUTPUT LIKE THIS:
Tbl_id W P date
1 1 3 2014-02-01
2 2 1 2014-02-04
I need Mysql Query to get output given in above..
You need to use SUM aggregate function for summation and a temp row number for Tbl_id.
select
#rwnm:=#rwnm+1 as Tbl_id,
sum(No_people) as No_people,
sum(Breakfast) as Breakfast,
sum(Lunch) as Lunch,
date
from my_table, ( select #rwnm := 0 ) rownums
group by date
You need the SUM() function, not the COUNT().
SELECT
SUM(No_people),
SUM(Breakfast),
SUM(Lunch),
`date`
FROM yourTable
GROUP BY `date`
I did not include the Tbl_id, because every column you select must be used with an aggregate function or be included in the group by clause. Otherwise it's undetermined which row of the group is selected. Selecting it anyway only works in MySQL, but it does not adhere to the SQL standard. If you want some kind of row number instead either Ravinder's approach or create one on application level (which certainly is easier).
UPDATE:
SELECT
SUM(booked_by = 'W') AS W,
SUM(booked_by = 'P') AS P,
`date`
FROM yourTable
GROUP BY `date`
You still need the SUM() function. booked_by = 'whatever' evaluates to true (1) or false (0).
If you want just the result without slno below query will work fine
SELECT
SUM(No_People) as No_People,
SUM(Breakfast) as Breakfast,
Sum(Lunch) as Lunch,
`date` as date
FROM table_Name
GROUP BY `date`
Output:
No_people Breakfast Lunch date
84 112 160 2014-02-11
116 96 118 2014-02-04
But if you also want serial no. to be displayed then below query will work
SELECT
#slno := #slno + 1 as slno
SUM(No_People) as No_People,
SUM(Breakfast) as Breakfast,
Sum(Lunch) as Lunch,
`date` as date
FROM table_Name, (select #slno := 0 ) sln
GROUP BY `date`
Output:
slno No_people Breakfast Lunch date
1 84 112 160 2014-02-11
2 116 96 118 2014-02-04
Consider the following data set...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,booked_by CHAR(1) NOT NULL
,date DATE NOT NULL
);
INSERT INTO my_table VALUES
(1,'W','2014-02-01'),
(2,'P','2014-02-01'),
(3,'P','2014-02-01'),
(4,'P','2014-02-01'),
(5,'W','2014-02-04'),
(6,'W','2014-02-04'),
(7,'P','2014-02-04');
Here's a pivot query...
SELECT date
, COUNT(CASE WHEN booked_by = 'W' THEN 'foo' END) W
, COUNT(CASE WHEN booked_by = 'P' THEN 'foo' END) P
FROM my_table
GROUP
BY date;
+------------+---+---+
| date | W | P |
+------------+---+---+
| 2014-02-01 | 1 | 3 |
| 2014-02-04 | 2 | 1 |
+------------+---+---+
In my opinion, a better idea (more flexible, more scalable) is simply to return a GROUPED (and, therefore, ordered) result set and handle the rest at in the presentation layer (e.g. a simple PHP loop)...
SELECT date,booked_by,COUNT(*) ttl FROM my_table GROUP BY date,booked_by;
+------------+-----------+-----+
| date | booked_by | ttl |
+------------+-----------+-----+
| 2014-02-01 | P | 3 |
| 2014-02-01 | W | 1 |
| 2014-02-04 | P | 1 |
| 2014-02-04 | W | 2 |
+------------+-----------+-----+