{"id":883,"date":"2022-01-21T10:38:37","date_gmt":"2022-01-21T15:08:37","guid":{"rendered":"http:\/\/gregorgonzalez.com.ve\/blog\/?p=883"},"modified":"2022-01-21T10:38:37","modified_gmt":"2022-01-21T15:08:37","slug":"usar-funcion-sum-con-case-oracle","status":"publish","type":"post","link":"https:\/\/gregorgonzalez.com.ve\/blog\/usar-funcion-sum-con-case-oracle\/","title":{"rendered":"Usar funci\u00f3n SUM con CASE &#8211; ORACLE"},"content":{"rendered":"<p>Trabajando en un reporte mensual, deb\u00eda separar por criterio el total generado en una sumatoria.<\/p>\n<p>Normalmente para separarlo se utiliza la agrupaci\u00f3n, ya tenemos la primera agrupaci\u00f3n que ser\u00eda por mes y la segunda seria por el criterio, como por ejemplo sumar el sueldo mensual de varios empleados pero diferenciando por el sueldo y bonos que tengan.<\/p>\n<p>Vamos a crear una tabla de pagos:<\/p>\n<pre class=\"lang:plsql decode:true\">CREATE TABLE pagos (\r\n    id number PRIMARY KEY NOT NULL,\r\n    id_empleado number NOT NULL,\r\n    fecha date NOT NULL,\r\n    tipo_pago VARCHAR2(10) NOT NULL,\r\n    monto number(18,2) NOT NULL\r\n);\r\n\r\nINSERT INTO pagos VALUES (1, 047, TO_DATE('2022-01-01','YYYY-MM-DD'), 'sueldo', 100.00);\r\nINSERT INTO pagos VALUES (2, 047, TO_DATE('2022-01-01','YYYY-MM-DD'), 'bono', 10.00);\r\nINSERT INTO pagos VALUES (3, 056, TO_DATE('2022-01-15','YYYY-MM-DD'), 'sueldo', 150.00);\r\nINSERT INTO pagos VALUES (4, 056, TO_DATE('2022-01-15','YYYY-MM-DD'), 'bono', 20.00);\r\nINSERT INTO pagos VALUES (5, 112, TO_DATE('2022-01-30','YYYY-MM-DD'), 'sueldo', 200.00);\r\nINSERT INTO pagos VALUES (6, 112, TO_DATE('2022-01-30','YYYY-MM-DD'), 'bono', 25.00);<\/pre>\n<p>&nbsp;<\/p>\n<table style=\"border-collapse: collapse; width: 300pt;\" border=\"0\" width=\"400\" cellspacing=\"0\" cellpadding=\"0\">\n<thead>\n<tr style=\"height: 15.0pt;\">\n<th style=\"height: 15.0pt; width: 60pt;\" width=\"80\" height=\"20\">id<\/th>\n<th style=\"width: 60pt;\" width=\"80\">id_empleado<\/th>\n<th style=\"width: 60pt;\" width=\"80\">fecha<\/th>\n<th style=\"width: 60pt;\" width=\"80\">tipo_pago<\/th>\n<th style=\"width: 60pt;\" width=\"80\">monto<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr style=\"height: 15.0pt;\">\n<td style=\"height: 15.0pt;\" align=\"right\" height=\"20\">1<\/td>\n<td align=\"right\">47<\/td>\n<td class=\"xl65\" align=\"right\">01\/01\/2022<\/td>\n<td>sueldo<\/td>\n<td align=\"right\">100<\/td>\n<\/tr>\n<tr style=\"height: 15.0pt;\">\n<td style=\"height: 15.0pt;\" align=\"right\" height=\"20\">2<\/td>\n<td align=\"right\">47<\/td>\n<td class=\"xl65\" align=\"right\">01\/01\/2022<\/td>\n<td>bono<\/td>\n<td align=\"right\">10<\/td>\n<\/tr>\n<tr style=\"height: 15.0pt;\">\n<td style=\"height: 15.0pt;\" align=\"right\" height=\"20\">3<\/td>\n<td align=\"right\">56<\/td>\n<td class=\"xl65\" align=\"right\">15\/01\/2022<\/td>\n<td>sueldo<\/td>\n<td align=\"right\">150<\/td>\n<\/tr>\n<tr style=\"height: 15.0pt;\">\n<td style=\"height: 15.0pt;\" align=\"right\" height=\"20\">4<\/td>\n<td align=\"right\">56<\/td>\n<td class=\"xl65\" align=\"right\">15\/01\/2022<\/td>\n<td>bono<\/td>\n<td align=\"right\">20<\/td>\n<\/tr>\n<tr style=\"height: 15.0pt;\">\n<td style=\"height: 15.0pt;\" align=\"right\" height=\"20\">5<\/td>\n<td align=\"right\">112<\/td>\n<td class=\"xl65\" align=\"right\">30\/01\/2022<\/td>\n<td>sueldo<\/td>\n<td align=\"right\">200<\/td>\n<\/tr>\n<tr style=\"height: 15.0pt;\">\n<td style=\"height: 15.0pt;\" align=\"right\" height=\"20\">6<\/td>\n<td align=\"right\">112<\/td>\n<td class=\"xl65\" align=\"right\">30\/01\/2022<\/td>\n<td>bono<\/td>\n<td align=\"right\">25<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<p>Para el reporte de total devengado por mes, solo ser\u00eda sumar todo el monto y agrupando por mes:<\/p>\n<pre class=\"lang:plsql decode:true\">SELECT to_char(fecha, 'MM-YYYY') mes, SUM(monto) AS total\r\nFROM pagos GROUP BY to_char(fecha, 'MM-YYYY');<\/pre>\n<p>&nbsp;<\/p>\n<table style=\"border-collapse: collapse; width: 120pt;\" border=\"0\" width=\"160\" cellspacing=\"0\" cellpadding=\"0\">\n<thead>\n<tr style=\"height: 15.0pt;\">\n<th style=\"height: 15.0pt; width: 60pt;\" width=\"80\" height=\"20\">mes<\/th>\n<th style=\"width: 60pt;\" width=\"80\">total<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr style=\"height: 15.0pt;\">\n<td class=\"xl65\" style=\"height: 15.0pt;\" align=\"right\" height=\"20\">01-2022<\/td>\n<td align=\"right\">505<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<p>Ahora para sumarlo por separado el sueldo del bono, solo se necesita agrupar adicionalmente por el tipo de pago, que ser\u00eda la columna tipo_pago:<\/p>\n<pre class=\"lang:plsql decode:true\">SELECT \r\n    to_char(fecha, 'MM-YYYY') mes,\r\n    tipo_pago,\r\n    SUM(monto) AS total\r\nFROM pagos GROUP BY to_char(fecha, 'MM-YYYY'), tipo_pago;<\/pre>\n<p>&nbsp;<\/p>\n<table style=\"border-collapse: collapse; width: 180pt;\" border=\"0\" width=\"240\" cellspacing=\"0\" cellpadding=\"0\">\n<thead>\n<tr style=\"height: 15.0pt;\">\n<th style=\"height: 15.0pt; width: 60pt;\" width=\"80\" height=\"20\">mes<\/th>\n<th style=\"width: 60pt;\" width=\"80\">tipo_pago<\/th>\n<th style=\"width: 60pt;\" width=\"80\">total<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr style=\"height: 15.0pt;\">\n<td class=\"xl65\" style=\"height: 15.0pt;\" align=\"right\" height=\"20\">01-2022<\/td>\n<td>bono<\/td>\n<td align=\"right\">55<\/td>\n<\/tr>\n<tr style=\"height: 15.0pt;\">\n<td class=\"xl65\" style=\"height: 15.0pt;\" align=\"right\" height=\"20\">01-2022<\/td>\n<td>sueldo<\/td>\n<td align=\"right\">450<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<p>Ok, el resultado funciona y podemos filtrar con un where si necesitamos uno u otro pero esto puede ser un doble trabajo o doble consulta y \u00bfQu\u00e9 hay del caso que para el reporte se necesiten dos columnas y no dos filas?<\/p>\n<p>Se complica porque se puede realizar de varias maneras: se puede hacer desde el lado de frontend como tambi\u00e9n manejando arrays en backend para agrupar por empleado; Hacer dos subquery que totalicen por separado con cada columna, pero esto implica duplicar el query y tambi\u00e9n los filtros en el where; Hacer concatenaci\u00f3n con la funci\u00f3n COALESCE y luego separarla en columnas desde c\u00f3digo, etc.<\/p>\n<p>Para este caso podemos usar un CASE en la funci\u00f3n SUM y as\u00ed poder separar en dos columnas sin tener que hacer grandes cambios a la consulta y se mantiene aquellos filtros usados en where.<\/p>\n<pre class=\"lang:plsql decode:true \">SELECT \r\n    to_char(fecha, 'MM-YYYY') mes,\r\n    SUM(CASE WHEN tipo_pago = 'sueldo' THEN monto ELSE 0 END) AS total_sueldos,\r\n    SUM(CASE WHEN tipo_pago = 'bono' THEN monto ELSE 0 END) AS total_bonos\r\nFROM pagos GROUP BY to_char(fecha, 'MM-YYYY');<\/pre>\n<p>&nbsp;<\/p>\n<table style=\"border-collapse: collapse; width: 240pt;\" border=\"0\" width=\"240\" cellspacing=\"0\" cellpadding=\"0\">\n<thead>\n<tr style=\"height: 15.0pt;\">\n<th style=\"height: 15.0pt; width: 60pt;\" width=\"80\" height=\"20\">mes<\/th>\n<th style=\"width: 60pt;\" width=\"80\">total_sueldos<\/th>\n<th style=\"width: 60pt;\" width=\"80\">total_bonos<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr style=\"height: 15.0pt;\">\n<td class=\"xl65\" style=\"height: 15.0pt;\" align=\"right\" height=\"20\">01-2022<\/td>\n<td align=\"right\">450<\/td>\n<td align=\"right\">55<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Es importante recordar que la funci\u00f3n SUM devolver\u00e1 NULL si la columna permite NULL y tampoco sino existe alg\u00fan registro, por ejemplo en el caso de que haya empleados sin bonos y debemos cambiarlo a cero 0 manualmente, ya sea con un NVL o con el ELSE para que sume cero.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Trabajando en un reporte mensual, deb\u00eda separar por criterio el total generado en una sumatoria. Normalmente para separarlo se utiliza la agrupaci\u00f3n, ya tenemos la primera agrupaci\u00f3n que ser\u00eda por mes y la segunda seria por el criterio, como por ejemplo sumar el sueldo mensual de varios empleados pero diferenciando por el sueldo y bonos [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":660,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"footnotes":""},"categories":[239],"tags":[335,336,55],"_links":{"self":[{"href":"https:\/\/gregorgonzalez.com.ve\/blog\/wp-json\/wp\/v2\/posts\/883"}],"collection":[{"href":"https:\/\/gregorgonzalez.com.ve\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gregorgonzalez.com.ve\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gregorgonzalez.com.ve\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/gregorgonzalez.com.ve\/blog\/wp-json\/wp\/v2\/comments?post=883"}],"version-history":[{"count":7,"href":"https:\/\/gregorgonzalez.com.ve\/blog\/wp-json\/wp\/v2\/posts\/883\/revisions"}],"predecessor-version":[{"id":890,"href":"https:\/\/gregorgonzalez.com.ve\/blog\/wp-json\/wp\/v2\/posts\/883\/revisions\/890"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/gregorgonzalez.com.ve\/blog\/wp-json\/wp\/v2\/media\/660"}],"wp:attachment":[{"href":"https:\/\/gregorgonzalez.com.ve\/blog\/wp-json\/wp\/v2\/media?parent=883"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gregorgonzalez.com.ve\/blog\/wp-json\/wp\/v2\/categories?post=883"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gregorgonzalez.com.ve\/blog\/wp-json\/wp\/v2\/tags?post=883"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}