Assuming you have a table with the following structure:
+-------+----------+
| CAMPO | TIPO |
+-------+----------+
| ID | NUMERIC |
| NOME | VARCHAR |
| TOTAL | NUMERIC |
| MES | DATE |
+-------+----------+
You could do something like:
WITH DADOS AS (
SELECT ID,
NOME,
TOTAL,
EXTRACT(MONTH FROM MES) MES,
EXTRACT(YEAR FROM MES) ANO,
RANK() OVER (PARTITION BY EXTRACT(YEAR_MONTH FROM MES) ORDER BY TOTAL DESC) RANKING
FROM TABELA1
)
SELECT ID,
NOME,
TOTAL,
MES,
ANO
FROM DADOS
WHERE RANKING < 11
Explanation
In this case we build a relationship using the WITH, in this relationship we have the ID, NOME, value TOTAL, MES, ANO and RANKING.
To build the RANKING we use the function RANK, and specify a partition, within a partition the count is restarted for each partition, in our case we use the ANO_MES as a partition and sort the values in a decreasing way (from the highest to the lowest).
This gives us a relationship that stays with this structure.
+-------+----------+
| CAMPO | TIPO |
+-------+----------+
| ID | NUMERIC |
| NOME | VARCHAR |
| TOTAL | NUMERIC |
| MES | NUMERIC |
| ANO | NUMERIC |
| RANK | NUMERIC |
+-------+----------+
Once armed with this relationship we only made one select, limiting RANK to the first 10.
How do we have a column for the MES and another to the ANO you can do a filtering with ease.
Considerations.
This approach does not return each month as a column, so if you want to do this, one possibility is to select several times the data relation, one for each month and filtering the month of each in the clause WHERE.