the null values are coming from the inner table this can be changed in a number of ways - lets tackle the null monthname first - change the order by to the month fields from the table that always has values in it
SELECT months.month, tbl.mnum, tbl.ynum, tbl.noflights FROM
months LEFT JOIN (
SELECT month(datefly) AS mnum, monthname(datefly) AS mname, year(datefly) AS ynum, COUNT(datefly) AS noflights FROM flights group BY year(datefly) DESC, month(datefly) DESC ) AS tbl
ON
months.month=tbl.mname
ORDER BY month
then make sure you are using the field month rather than the field mnum.
to ensure the noflights has a value in it you can move the count up to the outer query.
SELECT months.month, tbl.mnum, tbl.ynum, COUNT(tbl.datefly) AS noflights FROM
months LEFT JOIN (
SELECT month(datefly) AS mnum, monthname(datefly) AS mname, year(datefly) AS ynum, datefly FROM flights group BY year(datefly) DESC, month(datefly) DESC ) AS tbl
ON
months.month=tbl.mname
ORDER BY month
for the years you will need another field - I would add three fields to the month table as follows
CREATE TABLE months (
yearmonth varchar(20) primary key,
year int unsigned,
monthnumber int unsigned,
month varchar(20));
then add records like
INSERT INTO months VALUES
("2004January", 2004, 1, "January");
repeat as necessary
then change your query as follows:
SELECT months.yearmonth, months.month, months.year, COUNT(tbl.datefly) AS noflights FROM
months LEFT JOIN (
SELECT CONCAT(year(datefly, monthname(datefly)) AS ym, datefly FROM flights) AS tbl
ON
months.yearmonth=tbl.ym
GROUP BY yearmonth
ORDER BY year, monthnumber
let me know how that goes.