Here's a partial answer.
To begin with, Postgresql cannot have column names beginning with a digit. So you'll have to name the year_month columns differently. It could be "_2008_01" (note the leading underscore) or something like ym_2008_01. I'll assume the second naming convention.
First create the hexa_grid_pip table:
CREATE TABLE hexa_grid_pip AS
SELECT gid FROM hexa_grid;
This will make the new table with only one column, gid, using the gid values from the hexa_grid table. Now add all the other year_month columns:
ALTER TABLE hexa_grid_pip ADD COLUMN ym_2008_01 INTEGER,
ADD COLUMN ym_2008_02 INTEGER,
ADD COLUMN ym_2008_03 INTEGER,
ADD COLUMN ym_2008_04 INTEGER,
....
;
Now, you can update one of the month columns with an expression like:
UPDATE hexa_grid_pip SET ym_2008_01=(
SELECT COUNT(p.gid)
FROM points AS p, hexa_grid AS h
WHERE ST_Within(p.geom, h.geom) AND
date_part('year', p.datum) = 2008 AND
data_part('month',p.datum) = 1 AND
h.gid = hexa_grid_pip.gid
);
Now, what you'll want to do is wrap the above into a function which does two nested loops, over the 4 years and 12 months (this is just a skeleton example, not tested!):
DECLARE
yr integer :=2008;
mo integer :=1;
col text;
BEGIN
FOR yr IN 2008..2011 LOOP
FOR mo IN 1..12 LOOP
-- Make the column header
col='ym_' || to_char(yr, '9999') || '_' || to_char(mo,'99');
-- do the UPDATE similar to above, but with the yr, mo and col variables
UPDATE hexa_grid_pip SET col=(
SELECT COUNT(p.gid)
FROM points AS p, hexa_grid AS h
WHERE ST_Within(p.geom, h.geom) AND
date_part('year', p.datum) = yr AND
data_part('month',p.datum) = mo AND
h.gid = hexa_grid_pip.gid;
END LOOP;
END LOOP;
END;
Again, I've not tested the above. It will require debugging. HTH
Micha