diff --git a/src/libs/routes/spatial.js b/src/libs/routes/spatial.js
index 34241b3189e79e709c80b1fee33bcef025fc6c2f..d3f4e9b2d98a4710a32b301c9c85cbffae10535a 100644
--- a/src/libs/routes/spatial.js
+++ b/src/libs/routes/spatial.js
@@ -260,437 +260,75 @@ spatialApp.get('/sociodemographic', rqf.parse(), rqf.build(), (req, res, next) =
     });
 }, response('spatial'));
 
-spatialApp.get('/educational', (req, res, next) => {
+spatialApp.get('/educational', req.parse(), rqf.build(), (req, res, next) => {
     const censusYearQry = squel.select()
         .field('MAX(escola.ano_censo)', 'ano_censo')
         .from('escola')
         .toString();
 
-    const totalSchoolsQry = squel.select()
+    const totalSchoolsQry = req.sql.clone()
         .field('\'Brasil\'', 'name')
         .field('0', 'location')
-        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .field('COUNT(DISTINCT(escola.id))', 'total')
         .field('escola.ano_censo', 'census_year')
         .from('escola')
+        .join('turma', null, 'turma.ano_censo=escola.ano_censo AND turma.escola_id = escola.id')
         .where(`escola.ano_censo IN (${censusYearQry})`)
-        .where('escola.id_tipo_turma = 0')
+        .where('turma.tipo_turma_id = 0')
         .group('escola.ano_censo');
 
-    const schoolsPerLocationQry = squel.select()
+    const schoolsPerLocationQry = req.sql.clone()
         .field('\'Brasil\'', 'name')
-        .field('escola.tipo_localizacao', 'location')
+        .field('escola.cod_localizacao', 'location')
         .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
         .field('escola.ano_censo', 'census_year')
         .from('escola')
+        .join('turma', null, 'turma.ano_censo=escola.ano_censo AND turma.escola_id=escola.id')
         .where(`escola.ano_censo IN (${censusYearQry})`)
-        .where('escola.id_tipo_turma = 0')
-        .group('escola.tipo_localizacao')
+        .where('truma.tipo_turma_id = 0')
+        .group('escola.cod_localizacao')
         .group('escola.ano_censo')
-        .order('escola.tipo_localizacao');
+        .order('escola.cod_localizacao');
 
     const schoolClassYearQry = squel.select()
-        .field('MAX(turma.ano_censo)')
+        .field('MAX(matricula.ano_censo)')
         .from('turma')
         .toString();
 
-    const enrollmentsQry = squel.select()
+    const enrollmentsQry = req.sql.clone()
         .field('\'Brasil\'', 'name')
-        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
-        .field('turma.ano_censo', 'census_year')
-        .from('turma')
-        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
-        .where('turma.fk_tipo_turma_id <= 3')
-        .group('turma.ano_censo');
+        .field('COALESCE(COUNT(matricula.id), 0)', 'total')
+        .field('matricula.ano_censo', 'census_year')
+        .from('matricula')
+        .where(`matricula.ano_censo IN (${schoolClassYearQry})`)
+        .where('matricula.tipo <= 3')
+        .group('matricula.ano_censo');
 
     const enrollmentsPerAdmDepQry = squel.select()
         .field('\'Brasil\'', 'name')
-        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
-        .field('turma.ano_censo', 'census_year')
-        .field('dependencia_adm.nome', 'adm_dependency')
-        .from('turma')
-        .from('dependencia_adm')
-        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
-        .where('turma.fk_tipo_turma_id <= 3')
-        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
-        .group('turma.ano_censo')
+        .field('COALESCE(COUNT(matricula.id), 0)', 'total')
+        .field('matricula.ano_censo', 'census_year')
+        .field('dependencia_adm.nome', 'adm_dependency_name')
+        .from('matricula')
+        .join('dependencia_adm', null, 'matricula.dependencia_adm_id=dependencia_adm.id')
+        .where('matricula.tipo <= 3')
+        .where(`matricula.ano_censo IN (${schoolClassYearQry})`)
+        .group('matricula.ano_censo')
         .group('dependencia_adm.nome')
         .order('dependencia_adm.nome');
 
     const enrollmentsPerSchoolLevelQry = squel.select()
         .field('\'Brasil\'', 'name')
-        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
-        .field('turma.ano_censo', 'census_year')
-        .field('etapa_ensino.desc_etapa', 'school_level')
-        .from('turma')
-        .from('etapa_ensino')
-        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
-        .where('turma.fk_tipo_turma_id <= 3')
-        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
-        .group('turma.ano_censo')
-        .group('etapa_ensino.desc_etapa')
-        .group('etapa_ensino.pk_etapa_ensino_id')
-        .order('etapa_ensino.pk_etapa_ensino_id');
-
-    const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
-        "enrollment_per_school_level" ];
-    const querySet = [ totalSchoolsQry, schoolsPerLocationQry, enrollmentsQry,
-        enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry];
-    // wait until all queries finish or one of them fail
-    Promise.all(dbExecAll(querySet)).then((queryResults) => {
-        req.result = processResultSet(queryResults, queryLabels);
-        for(let label in req.result) {
-            for(let row of req.result[label]) {
-                if (row.hasOwnProperty('location')) {
-                    row.location = locationIdToStr(row.location);
-                }
-            }
-        }
-        next();
-    }).catch((error) => {
-        log.error(`[SQL query error] ${error}`);
-        next(error);
-    });
-}, response('location'));
-
-spatialApp.get('/educational/region/:id', (req, res, next) => {
-    const regionId = parseInt(req.params.id, 10);
-
-    const censusYearQry = squel.select()
-        .field('MAX(escola.ano_censo)', 'ano_censo')
-        .from('escola')
-        .toString();
-
-    const totalSchoolsQry = squel.select()
-        .field('regiao.nome', 'name')
-        .field('0', 'location')
-        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
-        .field('escola.ano_censo', 'census_year')
-        .from('escola')
-        .from('estado')
-        .from('regiao')
-        .where('escola.fk_estado_id = estado.pk_estado_id')
-        .where('estado.fk_regiao_id = regiao.pk_regiao_id')
-        .where(`regiao.pk_regiao_id = ${regionId}`)
-        .where(`escola.ano_censo IN (${censusYearQry})`)
-        .where('escola.id_tipo_turma = 0')
-        .group('regiao.nome')
-        .group('escola.ano_censo')
-        .order('regiao.nome');
-
-    const schoolsPerLocationQry = squel.select()
-        .field('regiao.nome', 'name')
-        .field('escola.tipo_localizacao', 'location')
-        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
-        .field('escola.ano_censo', 'census_year')
-        .from('escola')
-        .from('estado')
-        .from('regiao')
-        .where('escola.fk_estado_id = estado.pk_estado_id')
-        .where('estado.fk_regiao_id = regiao.pk_regiao_id')
-        .where(`regiao.pk_regiao_id = ${regionId}`)
-        .where(`escola.ano_censo IN (${censusYearQry})`)
-        .where('escola.id_tipo_turma = 0')
-        .group('regiao.nome')
-        .group('escola.tipo_localizacao')
-        .group('escola.ano_censo')
-        .order('regiao.nome')
-        .order('escola.tipo_localizacao');
-
-    const schoolClassYearQry = squel.select()
-        .field('MAX(turma.ano_censo)')
-        .from('turma')
-        .toString();
-
-    const enrollmentsQry = squel.select()
-        .field('regiao.nome', 'name')
-        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
-        .field('turma.ano_censo', 'census_year')
-        .from('turma')
-        .from('regiao')
-        .where('turma.fk_regiao_id = regiao.pk_regiao_id')
-        .where(`turma.fk_regiao_id = ${regionId}`)
-        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
-        .where('turma.fk_tipo_turma_id <= 3')
-        .group('turma.ano_censo')
-        .group('regiao.nome')
-        .order('regiao.nome');
-
-    const enrollmentsPerAdmDepQry = squel.select()
-        .field('regiao.nome', 'name')
-        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
-        .field('turma.ano_censo', 'census_year')
-        .field('dependencia_adm.nome', 'adm_dependency')
-        .from('turma')
-        .from('dependencia_adm')
-        .from('regiao')
-        .where('turma.fk_regiao_id = regiao.pk_regiao_id')
-        .where(`turma.fk_regiao_id = ${regionId}`)
-        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
-        .where('turma.fk_tipo_turma_id <= 3')
-        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
-        .group('turma.ano_censo')
-        .group('dependencia_adm.nome')
-        .group('regiao.nome')
-        .order('regiao.nome')
-        .order('dependencia_adm.nome');
-
-    const enrollmentsPerSchoolLevelQry = squel.select()
-        .field('regiao.nome', 'name')
-        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
-        .field('turma.ano_censo', 'census_year')
-        .field('etapa_ensino.desc_etapa', 'school_level')
-        .from('turma')
-        .from('etapa_ensino')
-        .from('regiao')
-        .where('turma.fk_regiao_id = regiao.pk_regiao_id')
-        .where(`turma.fk_regiao_id = ${regionId}`)
-        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
-        .where('turma.fk_tipo_turma_id <= 3')
-        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
-        .group('turma.ano_censo')
-        .group('etapa_ensino.desc_etapa')
-        .group('regiao.nome')
-        .group('etapa_ensino.pk_etapa_ensino_id')
-        .order('regiao.nome')
-        .order('etapa_ensino.pk_etapa_ensino_id');
-
-    const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
-        "enrollment_per_school_level" ];
-    const querySet = [ totalSchoolsQry, schoolsPerLocationQry, enrollmentsQry,
-        enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry];
-    // wait until all queries finish or one of them fail
-    Promise.all(dbExecAll(querySet)).then((queryResults) => {
-        req.result = processResultSet(queryResults, queryLabels);
-        for(let label in req.result) {
-            for(let row of req.result[label]) {
-                if (row.hasOwnProperty('location')) {
-                    row.location = locationIdToStr(row.location);
-                }
-            }
-        }
-        next();
-    }).catch((error) => {
-        log.error(`[SQL query error] ${error}`);
-        next(error);
-    });
-}, response('location'));
-
-spatialApp.get('/educational/state/:id', (req, res, next) => {
-    const stateId = parseInt(req.params.id, 10);
-
-    const censusYearQry = squel.select()
-        .field('MAX(escola.ano_censo)', 'ano_censo')
-        .from('escola')
-        .toString();
-
-    const totalSchoolsQry = squel.select()
-        .field('estado.nome', 'name')
-        .field('0', 'location')
-        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
-        .field('escola.ano_censo', 'census_year')
-        .from('escola')
-        .from('estado')
-        .where('escola.fk_estado_id = estado.pk_estado_id')
-        .where(`escola.fk_estado_id = ${stateId}`)
-        .where(`escola.ano_censo IN (${censusYearQry})`)
-        .where('escola.id_tipo_turma = 0')
-        .group('estado.nome')
-        .group('escola.ano_censo')
-        .order('estado.nome');
-
-    const schoolsPerLocationQry = squel.select()
-        .field('estado.nome', 'name')
-        .field('escola.tipo_localizacao', 'location')
-        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
-        .field('escola.ano_censo', 'census_year')
-        .from('escola')
-        .from('estado')
-        .where('escola.fk_estado_id = estado.pk_estado_id')
-        .where(`escola.fk_estado_id = ${stateId}`)
-        .where(`escola.ano_censo IN (${censusYearQry})`)
-        .where('escola.id_tipo_turma = 0')
-        .group('estado.nome')
-        .group('escola.tipo_localizacao')
-        .group('escola.ano_censo')
-        .order('estado.nome')
-        .order('escola.tipo_localizacao');
-
-    const schoolClassYearQry = squel.select()
-        .field('MAX(turma.ano_censo)')
-        .from('turma')
-        .toString();
-
-    const enrollmentsQry = squel.select()
-        .field('estado.nome', 'name')
-        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
-        .field('turma.ano_censo', 'census_year')
-        .from('turma')
-        .from('estado')
-        .where('turma.fk_estado_id = estado.pk_estado_id')
-        .where(`turma.fk_estado_id = ${stateId}`)
-        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
-        .where('turma.fk_tipo_turma_id <= 3')
-        .group('turma.ano_censo')
-        .group('estado.nome')
-        .order('estado.nome');
-
-    const enrollmentsPerAdmDepQry = squel.select()
-        .field('estado.nome', 'name')
-        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
-        .field('turma.ano_censo', 'census_year')
-        .field('dependencia_adm.nome', 'adm_dependency')
-        .from('turma')
-        .from('dependencia_adm')
-        .from('estado')
-        .where('turma.fk_estado_id = estado.pk_estado_id')
-        .where(`turma.fk_estado_id = ${stateId}`)
-        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
-        .where('turma.fk_tipo_turma_id <= 3')
-        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
-        .group('turma.ano_censo')
-        .group('dependencia_adm.nome')
-        .group('estado.nome')
-        .order('estado.nome')
-        .order('dependencia_adm.nome');
-
-    const enrollmentsPerSchoolLevelQry = squel.select()
-        .field('estado.nome', 'name')
-        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
-        .field('turma.ano_censo', 'census_year')
-        .field('etapa_ensino.desc_etapa', 'school_level')
-        .from('turma')
-        .from('etapa_ensino')
-        .from('estado')
-        .where('turma.fk_estado_id = estado.pk_estado_id')
-        .where(`turma.fk_estado_id = ${stateId}`)
-        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
-        .where('turma.fk_tipo_turma_id <= 3')
-        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
-        .group('turma.ano_censo')
-        .group('etapa_ensino.desc_etapa')
-        .group('etapa_ensino.pk_etapa_ensino_id')
-        .group('estado.nome')
-        .order('estado.nome')
-        .order('etapa_ensino.pk_etapa_ensino_id');
-
-    const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
-        "enrollment_per_school_level" ];
-    const querySet = [ totalSchoolsQry, schoolsPerLocationQry, enrollmentsQry,
-        enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry];
-    // wait until all queries finish or one of them fail
-    Promise.all(dbExecAll(querySet)).then((queryResults) => {
-        req.result = processResultSet(queryResults, queryLabels);
-        for(let label in req.result) {
-            for(let row of req.result[label]) {
-                if (row.hasOwnProperty('location')) {
-                    row.location = locationIdToStr(row.location);
-                }
-            }
-        }
-        next();
-    }).catch((error) => {
-        log.error(`[SQL query error] ${error}`);
-        next(error);
-    });
-}, response('location'));
-
-spatialApp.get('/educational/city/:id', (req, res, next) => {
-    const cityId = parseInt(req.params.id, 10);
-
-    const censusYearQry = squel.select()
-        .field('MAX(escola.ano_censo)', 'ano_censo')
-        .from('escola')
-        .toString();
-
-    const totalSchoolsQry = squel.select()
-        .field('municipio.nome', 'name')
-        .field('0', 'location')
-        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
-        .field('escola.ano_censo', 'census_year')
-        .from('escola')
-        .from('municipio')
-        .where('escola.fk_municipio_id = municipio.pk_cod_ibge')
-        .where(`escola.fk_municipio_id = ${cityId}`)
-        .where(`escola.ano_censo IN (${censusYearQry})`)
-        .where('escola.id_tipo_turma = 0')
-        .group('municipio.nome')
-        .group('escola.ano_censo')
-        .order('municipio.nome');
-
-    const schoolsPerLocationQry = squel.select()
-        .field('municipio.nome', 'name')
-        .field('escola.tipo_localizacao', 'location')
-        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
-        .field('escola.ano_censo', 'census_year')
-        .from('escola')
-        .from('municipio')
-        .where('escola.fk_municipio_id = municipio.pk_cod_ibge')
-        .where(`escola.fk_municipio_id = ${cityId}`)
-        .where(`escola.ano_censo IN (${censusYearQry})`)
-        .where('escola.id_tipo_turma = 0')
-        .group('municipio.nome')
-        .group('escola.tipo_localizacao')
-        .group('escola.ano_censo')
-        .order('municipio.nome')
-        .order('escola.tipo_localizacao');
-
-    const schoolClassYearQry = squel.select()
-        .field('MAX(turma.ano_censo)')
-        .from('turma')
-        .toString();
-
-    const enrollmentsQry = squel.select()
-        .field('municipio.nome', 'name')
-        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
-        .field('turma.ano_censo', 'census_year')
-        .from('turma')
-        .from('municipio')
-        .where('turma.fk_municipio_id = municipio.pk_cod_ibge')
-        .where(`turma.fk_municipio_id = ${cityId}`)
-        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
-        .where('turma.fk_tipo_turma_id <= 3')
-        .group('turma.ano_censo')
-        .group('municipio.nome')
-        .order('municipio.nome');
-
-    const enrollmentsPerAdmDepQry = squel.select()
-        .field('municipio.nome', 'name')
-        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
-        .field('turma.ano_censo', 'census_year')
-        .field('dependencia_adm.nome', 'adm_dependency')
-        .from('turma')
-        .from('dependencia_adm')
-        .from('municipio')
-        .where('turma.fk_municipio_id = municipio.pk_cod_ibge')
-        .where(`turma.fk_municipio_id = ${cityId}`)
-        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
-        .where('turma.fk_tipo_turma_id <= 3')
-        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
-        .group('turma.ano_censo')
-        .group('dependencia_adm.nome')
-        .group('municipio.nome')
-        .order('municipio.nome')
-        .order('dependencia_adm.nome');
-
-    const enrollmentsPerSchoolLevelQry = squel.select()
-        .field('municipio.nome', 'name')
-        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
-        .field('turma.ano_censo', 'census_year')
-        .field('etapa_ensino.desc_etapa', 'school_level')
-        .from('turma')
-        .from('etapa_ensino')
-        .from('municipio')
-        .where('turma.fk_municipio_id = municipio.pk_cod_ibge')
-        .where(`turma.fk_municipio_id = ${cityId}`)
-        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
-        .where('turma.fk_tipo_turma_id <= 3')
-        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
-        .group('turma.ano_censo')
+        .field('COALESCE(SUM(matricula.id), 0)', 'total')
+        .field('matricula.ano_censo', 'census_year')
+        .field('etapa_ensino.desc_etapa', 'school_level_name')
+        .from('matricula')
+        .join('etapa_ensino', null, 'matricula.etapa_ensino_id=etapa_ensino.id')
+        .where('matricula.tipo <= 3')
+        .where(`matricula.ano_censo IN (${schoolClassYearQry})`)
+        .group('matricula.ano_censo')
         .group('etapa_ensino.desc_etapa')
-        .group('etapa_ensino.pk_etapa_ensino_id')
-        .group('municipio.nome')
-        .order('municipio.nome')
-        .order('etapa_ensino.pk_etapa_ensino_id');
+        .order('etapa_ensino.desc_etapa');
 
     const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
         "enrollment_per_school_level" ];
@@ -711,7 +349,7 @@ spatialApp.get('/educational/city/:id', (req, res, next) => {
         log.error(`[SQL query error] ${error}`);
         next(error);
     });
-}, response('location'));
+}, response('spatial'));
 
 spatialApp.get('/educational/school_level', (req, res, next) => {
     const enrollmentsPerSchoolLevelYearQry = squel.select()