Forum > Databases

[HowTo SQLite] Setting an order within a Group-Concat

(1/1)

Zvoni:
In another Forum i helped out an User who was struggling with the following:
He had a table "tbl_employee" and a table "tbl_task", which were connected in an "m:m"-scenario via "tbl_emp_task"

He wanted to query his SQLite-Database to show for all employees their assigned tasks, but the tasks as a single text, preferably in alphabetic order
Example
employee    task
John Smith    task1, task4, task6
Robert Miller    task3, task4, task5

The GROUP_CONCAT-Function of SQLite doesn't have a ORDER BY-Modifier (Compared to other DBMS)
The documenation on sqlite.org even says:

--- Quote ---The order of the concatenated elements is arbitrary.
--- End quote ---
Though i think, the order is the order the elements are "presented", in case of a base-table my guess is the (hidden) row_id

Therefore i developed a solution as follows:
Setup for test-Database

--- Code: SQL  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---CREATE TABLE "tbl_employee" (    "ID"    INTEGER,    "FirstName"    TEXT NOT NULL,    "LastName"    TEXT NOT NULL,        PRIMARY KEY("ID"));CREATE TABLE "tbl_task" (    "ID"    INTEGER,    "Description"    TEXT NOT NULL,    PRIMARY KEY("ID"));CREATE TABLE "tbl_emp_task" (    "emp_id"    INTEGER,    "task_id"    INTEGER,    FOREIGN KEY("task_id") REFERENCES "tbl_task"("ID") ON UPDATE CASCADE ON DELETE CASCADE,    FOREIGN KEY("emp_id") REFERENCES "tbl_employee"("ID") ON UPDATE CASCADE ON DELETE CASCADE,    PRIMARY KEY("emp_id","task_id"));/*Testdata */INSERT INTO tbl_employee ("ID", "FirstName", "LastName") VALUES (1, 'Tom', 'Brown'), (2, 'Robert', 'Miller'), (3, 'John', 'Smith');INSERT INTO tbl_task ("ID", "Description") VALUES (1, 'answering phones'), (2, 'preparing meeting'), (3, 'receiving visitors'), (4, 'Maintaining security'), (5, 'Arranging couriers');INSERT INTO tbl_emp_task ("emp_id", "task_id") VALUES (1,1), (1,2), (1,4), (2,2),(2,3),(2,5);Note the combined Primary Key for tbl_emp_task consisting of the Foreign Keys.
That way we can make sure that each employee can be assigned a specific task only once


and here the solution:

--- Code: SQL  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---WITH CTE AS    (SELECT        ET.emp_ID AS EID,        T.Description AS TDESC    FROM tbl_emp_task AS ET    INNER JOIN tbl_task AS T    ON T.ID=ET.task_id    ORDER BY LOWER(T.Description))  /*For Case-Sensitive: ORDER BY T.Description --> No Lower-Function*/SELECT    E.FirstName || ' ' || E.LastName AS FullName,  /*Instead of constructing this within the SELECT we could also use a GENERATED Column*/    COALESCE(C.AssignedTasks, 'No assigned Tasks') AS AssignedTasksFROM tbl_employee AS ELEFT JOIN    (SELECT        EID,        GROUP_CONCAT(TDESC, ', ') AS AssignedTasks    FROM CTE GROUP BY EID) AS CON C.EID=E.IDGROUP BY E.FirstName || ' ' || E.LastName ORDER BY E.LastName, E.FirstNameThe order within the Group-Concat is Case-Insensitive!!
If you want Case-Sensitive order, remove the "Lower"-Function within the CTE.

btw: Using this you could use the returned Column "AssignedTasks" in DB-bound controls (DB-Grid)

Navigation

[0] Message Index

Go to full version