/*
 * Define a function to return a particular element from a comma-delimited
 * string. There is nothing already present in MySQL to do this.
 *
 * Create a table to hold the split tags, storing them in lower- and
 * upper-case form.
 *
 * Define a procedure to do the work of visiting every row in the 'eps' table
 * to extract the tags and place them in the 'tags' table with the episode id
 * they are associated with. This could be run on a periodic basis ('call
 * NormaliseEpisodeTags()') preceded by the statement 'DELETE FROM tags;'. The
 * 'lctags' column needs to be created with the statement 'UPDATE tags SET
 * lctag = LOWER(tag);'.
 *
 * With the 'tags' table filled then it can be queried for tag information as
 * shown in the examples below.
 *
 * 1. To count tag frequencies (case insensitive) and show the top 50:
 *
 * SELECT tag,lctag,COUNT(tag) AS freq FROM tags GROUP BY tag ORDER BY COUNT(tag) DESC LIMIT 50;
 *
 * 2. To return the episode numbers of shows tagged with a particular word:
 *
 * SELECT e.id,e.date,e.title,h.host FROM eps e JOIN hosts h ON e.hostid = h.hostid
 *      WHERE e.id IN (SELECT id FROM tags WHERE lctag = 'linux');
 *
 * ----------------------------------------------------------------------------
 * (These ideas were based upon the discussions at
 * https://stackoverflow.com/questions/17942508/sql-split-values-to-multiple-rows)
 * ----------------------------------------------------------------------------
 */

DELIMITER $$

/*
 * Create function 'strSplit'
 *
 * Arguments:
 *      x       - string to work on
 *      delim   - delimiter to split on
 *      pos     - starting position
 *
 */
DROP FUNCTION IF EXISTS strSplit;

CREATE FUNCTION strSplit(x VARCHAR(65000), delim VARCHAR(12), pos INTEGER)
    RETURNS VARCHAR(65000)
BEGIN
    DECLARE output VARCHAR(65000);
    SET output = TRIM(
        REPLACE(
            SUBSTRING(
                SUBSTRING_INDEX(x, delim, pos),
                LENGTH(SUBSTRING_INDEX(x, delim, pos - 1)) + 1
            ),
            delim,
            ''
        )
    );
    IF output = '' THEN
        SET output = null;
    END IF;
    RETURN output;
END $$

/*
 * Create procedure 'NormaliseEpisodeTags'
 *
 */
DROP PROCEDURE IF EXISTS NormaliseEpisodeTags;

CREATE PROCEDURE NormaliseEpisodeTags()
BEGIN
    DECLARE i INTEGER;

    SET i = 1;
    REPEAT
        INSERT INTO tags (id, tag, lctag)
            SELECT id, strSplit(tags, ',', i), lower(strSplit(tags, ',', i))
                FROM eps
                WHERE strSplit(tags, ',', i) IS NOT NULL;
        SET i = i + 1;
    UNTIL ROW_COUNT() = 0
    END REPEAT;
END $$

DELIMITER ;

/*
 * Create table 'tags'
 *
 */
DROP TABLE IF EXISTS tags;

CREATE TABLE tags (
    id int(5) NOT NULL,
    tag varchar(200),
    lctag varchar(200)
);

-- DROP INDEX tags_all ON tags;
CREATE UNIQUE INDEX tags_all ON tags (id,tag,lctag);

-- DROP INDEX tags_id ON tags;
CREATE INDEX tags_id ON tags (id);

-- DROP INDEX tags_tag ON tags;
CREATE INDEX tags_tag ON tags (tag);

-- DROP INDEX tags_lctag ON tags;
CREATE INDEX tags_lctag ON tags (lctag);


-- vim: syntax=sql:ts=8:ai:tw=78:et:fo=tcrqn21:comments+=b\:--
