Here I revisit the pivot table problem using the SQLite stored procedure
pattern and pure unmodified SQLite.  I am seeking feedback for improving
the brevity of the stored procedure presented here.  This time around I
went with generating pivot views instead of pivot tables since that was the
more popular modality in the remarks to my previous pivot table exhibit
using a TCL enabled version of shell.c.

Please feel free to use/modify/extend the stored procedure presented to
generate pivot view analytics for your own data tables and share any
improvements.  It will work without modification under any recent release
of SQLite for any suitable data table with uncomplicated column names.

Below, in three sections, I follow the usual composition format of this
forum.
Section 1: a simple data table specimen used in subsequent examples.
Section 2: exemplars of how to call the stored procedure.
Section 3: the stored procedure listing.

--SECTION 1-----------------------------------------------
--A trivial(for illustration) fruit sales table specimen--

sqlite> INSERT INTO quarterly_sales
VALUES(2016,2,'mangos',3),(2016,3,'peaches',2),(2017,2,'apples',7),(2017,2,'peaches',6),(2016,3,'mangos',12);

sqlite> SELECT * FROM quarterly_sales;
year        quarter     fruit       tons
----------  ----------  ----------  ----------
2016        2           mangos      3
2016        3           peaches     2
2017        2           apples      7
2017        2           peaches     6
2016        3           mangos      12

--SECTION 2----------------------------------------------------------------
--Examplar SQLite stored procedure pivot view generation calls--

--Total annual sales by fruit--
sqlite> INSERT INTO generate_pivot1_view
VALUES('quarterly_sales','year','fruit','tons','sum');

sqlite> SELECT * FROM pivot_view_quarterly_sales_year_fruit_tons_sum;
year        apples      mangos      peaches
----------  ----------  ----------  ----------
2016                    15          2
2017        7                       6

--Minimum quarterly sales by fruit--
sqlite> INSERT INTO generate_pivot1_view
VALUES('quarterly_sales','year','fruit','tons','min');

sqlite> SELECT * FROM pivot_view_quarterly_sales_year_fruit_tons_min;
year        apples      mangos      peaches
----------  ----------  ----------  ----------
2016                    3           2
2017        7                       6

--Maximum quarterly sales by fruit--
sqlite> INSERT INTO generate_pivot1_view
VALUES('quarterly_sales','year','fruit','tons','max');

sqlite> SELECT * FROM pivot_view_quarterly_sales_year_fruit_tons_max;
year        apples      mangos      peaches
----------  ----------  ----------  ----------
2016                    12          2
2017        7                       6

--Average quarterly sales by fruit--
sqlite> INSERT INTO generate_pivot1_view
VALUES('quarterly_sales','year','fruit','tons','avg');

sqlite> SELECT * FROM pivot_view_quarterly_sales_year_fruit_tons_avg;
year        apples      mangos      peaches
----------  ----------  ----------  ----------
2016                    7.5         2.0
2017        7.0                     6.0

--SECTION 3--------------------------------------------------------
--SQLite Stored Procedure "generate_pivot1_view" listing--

--Note that "pivot1" is the simplest case with just one(1) pivoting
aggregate.
--Pivot2,pivot3,...pivotN are left as an exercise for the reader.
--Other trivial improvements such as additional $row columns and HAVING
clause are also too obvious so yes, I am aware of those missing details.
Those minor things were also left as an exercise and omitted for brevity.

--However, please do comment with your suggestions for improving the
brevity of the procedure body in the areas of nesting depth of the string
replace or deep insights about quotation mark escaping/elimination that
will shorten this code.  As well, if an external helper extension function
would make this family of stored procedures easier to write, that code
would have to 1) be robust and 2) be made available, and 3) be trivial to
compile and load.

DROP VIEW IF EXISTS generate_pivot1_view;
CREATE VIEW generate_pivot1_view AS SELECT
(null)tbl,(null)row,(null)col1,(null)val1,(null)aggfn1;

DROP TRIGGER IF EXISTS generate_pivot1_view;
CREATE TRIGGER generate_pivot1_view INSTEAD OF INSERT ON
generate_pivot1_view
BEGIN
SELECT eval(replace(replace(replace(replace(replace(replace(
'DROP VIEW IF EXISTS pivot_view_$tbl_$row_$col1_$val1_$aggfn1;CREATE VIEW
pivot_view_$tbl_$row_$col1_$val1_$aggfn1 '
||'AS SELECT $row, $cols FROM $tbl GROUP BY $row'
,'$tbl',new.tbl),'$row',new.row),'$col1',new.col1),'$val1',new.val1),'$aggfn1',new.aggfn1)
,'$cols',(
  SELECT eval(replace(replace(replace(replace(
    'SELECT group_concat(''$aggfn1(CASE WHEN $col1=''||quote(col)||'' THEN
$val1 END)''||col) '
    ||'FROM (SELECT DISTINCT ($col1)col FROM $tbl ORDER BY col)'

,'$tbl',new.tbl),'$col1',new.col1),'$val1',new.val1),'$aggfn1',new.aggfn1))cols

  )
))ddl;
END;

--------------------------------------------------------------------------------------
[FYI.  The SQLite eval extension is part of the SQLite distribution and is
presently located at https://www.sqlite.org/src/artifact/f971962e92ebb8b0
]
_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to