MySQL Update Inner Join Aliases - mysql

I'm trying to run this query:
UPDATE anothertable
INNER JOIN (SELECT *,
LEAST(table1.from_price, table2.from_price, table3.from_price) AS cheapestPrice
FROM (SELECT * FROM table1 v WHERE hotelid >= 1
UNION
SELECT * FROM table2 c WHERE hotelid >= 1
UNION
SELECT * FROM table3 k WHERE hotelid >= 1) AS temp
GROUP BY temp.hotelid, temp.country) AS i ON anothertable.id = i.hotelid
AND anothertable.country = i.country
SET price = i.cheapestPrice,
op = i.to
However I cannot get the LEAST function to get access to a field called "from_price".
Ideas?

You should use Min instead of Least:
Update anothertable
Join (
Select hotelid, country, to
, Min(from_price) AS cheapestPrice
From (
Select hotelid, country, from_price, to
From table1 v
Where hotelid >= 1
Union
Select hotelid, country, from_price, to
From table2 c
Where hotelid >= 1
Union
Select hotelid, country, from_price, to
From table3 k
Where hotelid >= 1
) AS temp
Group By temp.hotelid, temp.country, temp.to
) As i
On anothertable.id = i.hotelid
And anothertable.country = i.country
Set price = i.cheapestPrice
, op = i.to
Edit
As pointed out in comments, I omitted the to column from the inner temp query. However, it occurs to me that it isn't clear how to should be included because you are using an awful feature of MySQL with respect to declaring the Group By columns. I'm assuming that you need to include to in the Group By however if that is not the case, you should be explicit about what aggregate function it should use on the to column.
Here's an alternate where I use Min on the to column:
Update anothertable
Join (
Select temp.hotelid, temp.country
, Min(temp.to) As to
, Min(temp.from_price) AS cheapestPrice
From (
Select v.hotelid, v.country, v.from_price, v.to
From table1 v
Where hotelid >= 1
Union
Select c.hotelid, c.country, c.from_price, c.to
From table2 c
Where hotelid >= 1
Union
Select k.hotelid, k.country, k.from_price, k.to
From table3 k
Where hotelid >= 1
) AS temp
Group By temp.hotelid, temp.country
) As i
On anothertable.id = i.hotelid
And anothertable.country = i.country
Set price = i.cheapestPrice
, op = i.to

Related

SQL: How to get cells by 2 last dates from 3 different tables?

I have 3 tables (stars mach the ids from the table before):
product:
prod_id* prod_name prod_a_id prod_b_id prod_user
keywords:
key_id** key_word key_prod* kay_country
data:
id dat_id** dat_date dat_rank_a dat_traffic_a dat_rank_b dat_traffic_b
I want to run a query (in a function that gets a $key_id) that outputs all these columns but only for the last 2 dates(dat_date) from the 'data' table for the key_id inserted - so that for every key_word - I have the two last dat_dates + all the other variables included in my SQL query:
So... This is what I have so far. and I don't know how to get only the MAX vars. I tried using "max(dat_date)" in different ways that didn't work.
SELECT prod_id, prod_name, prod_a_id, prod_b_id, key_id, key_word, kay_country, dat_date, dat_rank_a, dat_rank_b, dat_traffic_a, dat_traffic_b
FROM keywords
INNER JOIN data
ON keywords.key_id = data.dat_id
INNER JOIN prods
ON keywords.key_prod = prods.prod_id
Is there a possability to do this with only one query?
EDIT (FOR IgorM):
public function newnew() {
$query = $this->db->query('WITH CTE AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY dat_id ORDER BY dat_date ASC) AS
RowNo FROM data
)
SELECT *
FROM CTE
INNER JOIN keywords
ON keywords.key_id = CTE.dat_id
INNER JOIN prods
ON keywords.key_prod = prods.prod_id
WHERE RowNo < 3
');
$result = $query->result();
return $result;
}
This is the error on the output:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CTE AS ( SELECT *, ROW_NUMBER() OVER (' at line 1
WITH CTE AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY dat_id ORDER BY dat_date ASC) AS RowNo FROM data ) SELECT * FROM CTE INNER JOIN keywords ON keywords.key_id = CTE.dat_id INNER JOIN prods ON keywords.key_prod = prods.prod_id WHERE RowNo < 3
For SQL
WITH CTE AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY dat_id ORDER BY dat_date ASC) AS
RowNo FROM data
)
SELECT *
FROM CTE
INNER JOIN keywords
ON keywords.key_id = CTE.dat_id
INNER JOIN prods
ON keywords.key_prod = prods.prod_id
WHERE RowNo < 3
For MySQL (not tested)
SET #row_number:=0;
SET #dat_id = '';
SELECT *,
#row_number:=CASE WHEN #dat_id=dat_id THEN #row_number+1 ELSE 1 END AS row_number,
#dat_id:=dat_id AS dat_id_row_count
FROM data d
INNER JOIN keywords
ON keywords.key_id = d.dat_id
INNER JOIN prods
ON keywords.key_prod = prods.prod_id
WHERE d.row_number < 3
The other approach is self joining. I don't want to take credit for somebody else's job, so please look on the following example:
ROW_NUMBER() in MySQL
Look for the following there:
SELECT a.i, a.j, (
SELECT count(*) from test b where a.j >= b.j AND a.i = b.i
) AS row_number FROM test a
If you only want to do this for one key_id at a time (as alluded to in your responses to other answers) and only want two rows, you can just do:
SELECT p.prod_id,
p.prod_name,
p.prod_a_id,
p.prod_b_id,
k.key_id,
k.key_word,
k.key_country,
d.dat_date,
d.dat_rank_a,
d.dat_rank_b,
d.dat_traffic_a,
d.dat_traffic_b
FROM keywords k
JOIN data d
ON k.key_id = d.dat_id
JOIN prods p
ON k.key_prod = p.prod_id
WHERE k.key_id = :key_id /* Bind in key id */
ORDER BY d.dat_date DESC
LIMIT 2;
Whether you want this depends on your data structure and whether there is more than one key/prod combination per date.
Another option limiting just the data rows would be:
SELECT p.prod_id,
p.prod_name,
p.prod_a_id,
p.prod_b_id,
k.key_id,
k.key_word,
k.key_country,
d.dat_date,
d.dat_rank_a,
d.dat_rank_b,
d.dat_traffic_a,
d.dat_traffic_b
FROM keywords k
JOIN (
SELECT dat_id,
dat_date,
dat_rank_a,
dat_rank_b,
dat_traffic_a,
dat_traffic_b
FROM data
WHERE dat_id = :key_id /* Bind in key id */
ORDER BY dat_date DESC
LIMIT 2
) d
ON k.key_id = d.dat_id
JOIN prods p
ON k.key_prod = p.prod_id;
If you want some kind of grouped results for all the keywords, you'll need to look at the other answers.
I think a window function is the best way to go. without knowing a lot about the structure of the data you can try a subquery of what you are trying to restrict and then joining that to the rest of the data. Then within the where clause restrict the rows you pull back.
select p.prod_id, p.prod_name, p.prod_a_id, p.prod_b_id,
t.key_id, t.key_word, t.kay_country, t.dat_date,
t.dat_rank_a, t.dat_rank_b, t.dat_traffic_a, t.dat_traffic_b
from
(
select
k.key_id, k.key_word, k.kay_country, d.dat_date, d.dat_rank_a,
d.dat_rank_b, d.dat_traffic_a, d.dat_traffic_b,
row_number() over (partition by dat_id order by dat_date desc) as 'RowNum'
from keywords as k
inner join
data as d on k.key_id = d.dat_id
) as t
inner join
prods as p on t.key_prod = p.prod_id
where tmp.RowNum <=2
This is a "groupwise max" problem. Reference. CTE does not exist in MySQL.
I'm not totally clear on how your tables are linked, but here is a stab:
SELECT
*
FROM
( SELECT #prev := '', #n := 0 ) init
JOIN
( SELECT #n := if(k.key_id != #prev, 1, #n + 1) AS n,
#prev := k.key_id,
d.*, k.*, p.*
FROM data d
JOIN keywords k ON k.key_id = d.dat_id
JOIN prods p ON k.key_prod = p.prod_id
ORDER BY
k.key_id ASC,
d.dat_date ASC
) x
WHERE n <= 2
ORDER BY k.key_id, n;
you can use this query:
select prod_id, prod_name, prod_a_id, prod_b_id, key_id, key_word,
kay_country, dat_date, dat_rank_a, dat_rank_b, dat_traffic_a, dat_traffic_b
from keywords where dat_date in (
SELECT MAX(dat_date) FROM keywords temp_1
where temp_1.prod_id = keywords.prod_id
union all
SELECT MAX(dat_date) FROM keywords
WHERE dat_date NOT IN (SELECT MAX(dat_date ) FROM keywords temp_2 where
temp_2.prod_id = keywords.prod_id)
)

MySQL: Grouped by hour, need to show all hours, null where no data

Here's the query:
SELECT h.idhour, h.`hour`, outnumber, count(*) as `count`, sum(talktime) as `duration`
FROM (
SELECT
`cdrs`.`dcustomer` AS `dcustomer`,
(CASE
WHEN (`cdrs`.`cnumber` like "02%") THEN '02'
WHEN (`cdrs`.`cnumber` like "05%") THEN '05'
END) AS `outnumber`,
FROM_UNIXTIME(`cdrs`.`start`) AS `start`,
(`cdrs`.`end` - `cdrs`.`start`) AS `duration`,
`cdrs`.`talktime` AS `talktime`
FROM `cdrs`
WHERE `cdrs`.`start` >= #_START and `cdrs`.`start` < #_END
AND `cdrs`.`dtype` = _LATIN1'external'
GROUP BY callid
) cdr
JOIN customers c ON c.id = cdr.dcustomer
LEFT JOIN hub.hours h ON HOUR(cdr.`start`) = h.idhour
WHERE (c.parent = _ID or cdr.dcustomer = _ID or c.parent IN
(SELECT id FROM customers WHERE parent = _ID))
GROUP BY h.idhour, cdr.outnumber
ORDER BY h.idhour;
The above query results skips the hours where there is no data, but I need to show all hours (00:00 to 23:00) with null or 0 values. How can I do this?
SELECT h.idhour
, h.hour
,IFNULL(outnumber,'') AS outnumber
,IFNULL(cdr2.duration,0) AS duration
,IFNULL(output_count,0) AS output_count
FROM hub.hours h
LEFT JOIN (
SELECT HOUR(start) AS start,outnumber, SUM(talktime) as duration ,COUNT(1) AS output_count
FROM
(
SELECT cdrs.dcustomer AS dcustomer
, (CASE WHEN (cdrs.cnumber like "02%") THEN '02' WHEN (cdrs.cnumber like "05%") THEN '05' END) AS outnumber
, FROM_UNIXTIME(cdrs.start) AS start
, (cdrs.end - cdrs.start) AS duration
, cdrs.talktime AS talktime
FROM cdrs cdrs
INNER JOIN customers c ON c.id = cdrs.dcustomer
WHERE cdrs.start >= #_START and cdrs.start < #_END AND cdrs.dtype = _LATIN1'external'
AND
(c.parent = _ID or cdrs.dcustomer = _ID or c.parent IN (SELECT id FROM customers WHERE parent = _ID))
GROUP BY callid
) cdr
GROUP BY HOUR(start),outnumber
) cdr2
ON cdr2.start = h.idhour
ORDER BY h.idhour
You need a table with all hours, nothing else.
Then use LEFT JOIN with the hours table on the "left" and your current query on the "right":
SELECT b.*
FROM hours h
LEFT JOIN ( ... ) b ON b.hr = h.hr
WHERE h.hr BETWEEN ... AND ...
ORDER BY hr;
Any missing hours will be NULLs in b.*.

Is it possible to simplify this SQL statement with multiple subqueries and JOINs

I've spent a couple of days creating this rather complicated SQL statement, and it now gives me exactly what I want. Now I'm wondering if there is a better/simpler way to do it. Also MySQL wont let me CREATE VIEW on this statement
SELECT name, a.user, liste, c.order, total_1kr, total_5kr, total_8kr, total_10kr, total_paid, differens, sbdato, spaid, sbreg, sfdato, sforbrug, sfreg
FROM (SELECT t.user, t.paid AS spaid, t.dato AS sbdato, t.registrant AS sbreg FROM(
SELECT user,MAX(dato) AS maksdato
FROM g_kiosk_f WHERE paid!=0
GROUP BY user) AS x
JOIN g_kiosk_f AS t ON x.user =t.user
AND x.maksdato = t.dato) AS a
JOIN (SELECT s.user, (s.1kr+(s.5kr)*5+(s.8kr)*8+(s.10kr)*10) AS sforbrug, s.dato AS sfdato, s.registrant AS sfreg FROM(
SELECT user,MAX(dato) AS maksdato
FROM g_kiosk_f WHERE 1kr!=0 OR 5kr!=0 OR 8kr!=0 OR 10kr!=0
GROUP BY user) AS y
JOIN g_kiosk_f AS s ON y.user=s.user
AND y.maksdato=s.dato) AS b
JOIN (SELECT t1.name, t2.user, t1.liste, t1.order, sum( t2.1kr ) AS total_1kr, sum( t2.5kr ) *5 AS total_5kr, sum( t2.8kr ) *8 AS total_8kr, sum( t2.10kr ) *10 AS total_10kr, sum( t2.paid ) AS total_paid, ( sum( t2.1kr ) + sum( t2.5kr ) *5 + sum( t2.8kr ) *8 + sum( t2.10kr ) *10 - sum( t2.paid )) AS differens
FROM g_kiosk_users AS t1
INNER JOIN g_kiosk_f AS t2 ON t1.nr = t2.user
GROUP BY t2.user
ORDER BY t1.name ASC) AS c
ON a.user=b.user AND a.user=c.user
I have a table 'g_kiosk_f' containing id (user), date (dato), 5 kinds of transactions (1kr, 5kr, 8kr, 10kr, and paid) a cashier (registrant). Another table, 'g_kiosk_users', contains name and id (nr).
I want a result set showing
the date, registrant and amount of newest transaction where paid!=0
the date, registrant and amount of newest transaction where 1kr!=0, 5kr!=0, 8kr!=0 or 10kr!=0
the total difference of sum(1kr+5kr+8kr+10kr) and sum(paid)
So the result should look something like
Name | id | difference | newest paid date | newest paid registrant | newest paid amount | newest kr date | newest kr registrant | newest kr amount |
In the above I've included the numbers needed to do the difference calculation by hand, because it was needed at some point, but is now obsolete. Does any of this even make sense?
It seems like it should be possible to rewrite you query like this:
SELECT t1.name AS name, a.user AS user, t1.liste, t1.order,
SUM(t2.1kr) AS total_1kr, SUM(t2.5kr) * 5 AS total_5kr,
SUM(t2.8kr) AS total_8kr, SUM(t2.10kr) * 5 AS total_10kr,
SUM(52.paid) AS total_paid,
SUM(t2.1kr + 5 * tt.5kr + 8 * t2.8kr + 10 * t2.10kr)
-SUM(t2.paid) AS differens
a.dato AS sbdato, a.paid AS spaid, a.registrant as sbreg,
b.dato as sfdato,
(b.1kr+(b.5kr)*5+(b.8kr)*8+(b.10kr)*10) AS sforbrug,
b.registrant AS sfreg
FROM g_kiosk_f AS a
INNER JOIN (SELECT user, MAX(dato) FROM g_kiosk_f
WHERE paid != 0
GROUP BY user) AS a2
ON a.user = a2.user AND a.dato = a2.dato
INNER JOIN g_kiosk_f as b ON b.user = a.user
INNER JOIN (SELECT user, MAX(dato) FROM g_kiosk_f
WHERE 1kr!=0 OR 5kr!=0 OR 8kr!=0 OR 10kr!=0
GROUP BY user) AS b2
ON b.user = b2.user AND b.dato = b2.dato
INNER JOIN g_kiosk_f as t2 ON t2.user = a.user
INNER JOIN g_kiosk_users as t1 ON t1.nr = t2.user
GROUP BY a.user
ORDER BY name ASC

Select query with condition for the column from the second table

I have 2 tables (THour_IN and THour_OUT) that have identical schemas:
Columns for THour_IN: Name|date|HourIN
Colums for THour_OUT: Name|date|HourOUT
I make query:
SELECT THour_IN.Name, THour_IN.date, THour_IN.HourIN, THour_OUT.HourOUT FROM THour_IN LEFT JOIN THour_OUT ON (Hour_IN.Name = THour_OUT.Name) AND (Hour_IN.date = THour_OUT.date);
But this is not correct in my case, because I have multiple rows wtih the same date in the tables. The result is:
Name date HourIN HourOUT
AAA 24/11/2013 17:33:06 20:33:27
AAA 24/11/2013 17:33:06 16:36:06
AAA 24/11/2013 07:33:27 20:33:27
AAA 24/11/2013 07:33:27 16:36:06
BBB 18/11/2013 16:36:06
BBB 19/11/2013 07:33:30
BBB 21/11/2013 07:29:24 08:33:22
BBB 22/11/2013 07:33:30 16:34:53
It should be for date 24/11/2013 First HourIN(07:33:27) with Fisrt HourOUT (16:36:06), Second HourIN (17:33:06) with Second HourOUT (20:33:06) Any ideas?
Build segments, then intersect segments.
SELECT
P1.Name, P1.date, P1.HourIN, P1.HourOUT
FROM (
SELECT
I.Name, I.date, I.HourIN, O.HourOUT
FROM
THour_IN AS I
LEFT JOIN THour_OUT AS O
ON (I.Name = O.Name) AND (I.date = O.date)
AND I.HourIN < H.HourOUT
) AS P1
INNER JOIN (
SELECT
I.Name, I.date, I.HourIN, O.HourOUT
FROM
THour_IN AS I
LEFT JOIN THour_OUT AS O
ON (I.Name = O.Name) AND (I.date = O.date)
AND I.HourIN < H.HourOUT
) AS P2
ON P1.name = P2.name AND P1.date = P2.date
AND P1.HourIN <> P2.HourIN and P1.HourOUT <> P2.HourOUT
AND P1.HourOUT > P2.HourIN
AND (P1.HourIN = P2.HourIN AND P1.HourOUT < P2.HourOUT
OR P1.HourIN > P2.HourIN AND P1.HourOUT = P2.HourOUT)
You could use something like so:
SELECT
t.Name,
t.Date,
t.HourIN, (
SELECT Top 1 HourOut
FROM THourOUT o
WHERE o.Name=t.Name AND o.Date=t.date And o.HourOUT>t.HourIN
ORDER BY o.HourOUT,o.ID ) AS HrOut
FROM THourIN AS t
ORDER BY t.Date, t.HourIN;
Note that I have added an ID to the OUT table to ensure that top 1 does not return duplicates.
Here is an example of inserting missing values. It depends on a Numbers table containing integers from 0 or 1 to the highest number of missing values. A number table is useful in many ways.
INSERT INTO thourin
(name,
[date])
SELECT q.name,
q.DATE
FROM (SELECT Outs.name,
Outs.DATE,
Outs.countofout,
Ins.countofin
FROM (SELECT o.name,
o.DATE,
Count(o.name) AS CountOfOut
FROM thourout o
GROUP BY o.name,
o.DATE) AS Outs
LEFT JOIN (SELECT t.name,
t.DATE,
Count(t.name) AS CountOfIn
FROM thourin t
GROUP BY t.name,
t.DATE) AS Ins
ON ( Outs.name = Ins.name )
AND ( Outs.DATE = Ins.DATE )
WHERE (( ( Ins.countofin ) <> [countofout]
OR ( Ins.countofin ) IS NULL ))) AS q,
numbers AS n
WHERE (( ( n.counter ) > 0
AND ( n.counter ) <= [countofout] - [countofin] ))

MySQL: Using the dates in a between condition for the results

I have a SQL statement in which I do this
... group by date having date between '2010-07-01' and '2010-07-10';
The result looks like:
sum(test) day
--------------------
20 2010-07-03
120 2010-07-07
33 2010-07-09
42 2010-07-10
So I have these results, but is it possible, that I can write a statement that returns me for every day in the "between" condition a result row in this kind:
sum(test) day
--------------------
0 2010-07-01
0 2010-07-02
20 2010-07-03
0 2010-07-04
0 2010-07-05
0 2010-07-06
120 2010-07-07
... ...
42 2010-07-10
Otherwise, if this is not possible, I have to do it in my program logic.
Thanks a lot in advance & Best Regards.
Update: Perhaps it will be better if I will show you the full SQL statement:
select COALESCE(sum(DUR), 0) AS "r", 0 AS "opt", DATE_FORMAT(date, '%d.%m.%Y') AS "day" from (
select a.id as ID, a.dur as DUR, DATE(FROM_UNIXTIME(REVTSTMP / 1000)) as date,
a_au.re as RE, a_au.stat as STAT from b_c
join c on b_c.c_id = c.id
join a on c.id = a.c_id
join a_au on a.id = a_au.id
join revi on a_au.re = revi.re
join (
select a.id as ID, DATE(FROM_UNIXTIME(REVTSTMP / 1000)) as date,
max(a_au.re) as MAX_RE from b_c
join c on b_c.c_id = c.id
join a on c.id = a.c_id
join a_au on a.id = a_au.id
join revi on a_au.re = revi.re
where b_c.b_id = 30 group by ID, date) x on
x.id = a.id and x.date = date and x.MAX_RE = a_au.rev
where a_au.stat != 7
group by ID, x.date)
AS SubSelTable where date between '2010-07-01' and '2010-07-15' group by date;
Update:
My new SQL statement (-> Dave Rix):
select coalesce(`theData`.`real`, 0) as 'real', 0 as 'opt', DATE_FORMAT(`DT`.`ddDate`, '%d.%m.%Y') as 'date'
from `dimdates` as DT
left join (
select coalesce(sum(DUR), 0) AS 'real', 0 AS 'opt', date
from (
select a.id as ID, a.dur as DUR, DATE(FROM_UNIXTIME(REVTSTMP / 1000)) as date, a_au.RE as RE, a_au.stat as STAT
from b_c
join c on b_c.c_id = c.id
join a on c.id = a.c_id
join a_au on a.id = a_au.id
join revi on a_au.RE = revi.RE
join (
select a.id as ID, DATE(FROM_UNIXTIME(REVTSTMP / 1000)) as date, max(a_au.RE) as MAX_RE
from b_c
join c on b_c.c_id = c.id
join a on c.id = a.c_id
join a_au on a.id = a_au.id
join revi on a_au.RE = revi.RE
where b_c.b_id = 30 GROUP BY ID, date
) x
on x.id = a.id and x.date = date and x.MAX_RE = a_au.RE
where a_au.stat != 20
group by ID, x.date
) AS SubTable
where date between '2010-07-01' and '2010-07-10' group by date) AS theData
ON `DT`.`ddDate` = `theData`.`date` where `DT`.`ddDate` between '2010-07-01' and '2010-07-15';
Put the Between Logic in a Where Clause
Select Sum(day), day
From Table
Where day Between date1 and date2
Group By day
EDIT:
Having should only be used to filter data in the aggregates... i.e.
Having Sum(day) > 10
Check out my answer to the following question;
Select all months within given date span, including the ones with 0 values
This may be just what you are looking for :)
You can modify your query above as follows (you could integrate this, but this way is simpler!);
SELECT COALESCE(`theData`.`opt`, 0), `DT`.`myDate`
FROM `dateTable` AS DT
LEFT JOIN (
... INSERT YOUR QUERY HERE ...
) AS theData
ON `DT`.`myDate` = `theData`.`date`
and you will also need to change the DATE_FORMAT(date, '%d.%m.%Y') AS "day" in your query to just date
E.g.
select COALESCE(sum(DUR), 0) AS "r", 0 AS "opt", `date` from
As for #OMG Ponies answer, you will need to pre-populate the dateTable with plenty of rows of data!
Does anyone know how I can post my SQL dump of this table as a file which can be attached? It's quite big, but can be useful...
Assuming that your date column is a DATETIME column, you need to use something to change time values to be the same for proper grouping to happen. IE:
SELECT SUM(t.test),
DATE_FORMAT(t.date, '%Y-%m-%d') AS day
FROM TABLE t
WHERE t.date BETWEEN #start AND #end
GROUP BY DATE_FORMAT(t.date, '%Y-%m-%d')
But if there's no record for a given date, the date will not appear in the result set. In other words, no dates with zero will appear in your output.
To solve that, you need to LEFT JOIN to a table of dates, which MySQL doesn't have the ability to generate. It can't even generate a list of numbers, so you have to create a table with a single column:
DROP TABLE IF EXISTS `example`.`numbers`;
CREATE TABLE `example`.`numbers` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
...and populate it:
INSERT INTO numbers (id) VALUES (NULL)
...before you can use the number value to generate a list of dates using the DATE_ADD function:
SELECT COALESCE(SUM(t.test), 0),
x.the_date AS day
FROM (SELECT DATE_FORMAT(DATE_ADD(NOW(), INTERVAL n.id-1 DAY), '%Y-%m-%d') AS the_date
FROM NUMBERS n) x
LEFT JOIN your_table yt ON DATE_FORMAT(yt.date, '%Y-%m-%d') = x.the_date
WHERE x.the_date BETWEEN #start AND #end
GROUP BY x.the_date