Search code examples
pythonsqliteleft-joingroup-concat

Python / Sqlite3: LEFT JOIN with GROUP_CONCAT


I have 2 Tables:

Tasks:                     Predecessors:

ID | Task | Team           ID | TaskID | PredecessorID
---+------+------          ---+--------+--------------
1  | A    | 1              1  | 1      | None
2  | B    | 1              2  | 2      | 1 
3  | C    | 2              3  | 3      | 1
4  | D    | 2              4  | 3      | 2
                           5  | 4      | None

I want to select all Tasks from Team 2 and add the Predecessors for each Task separated by commas in that form:

ID | Task | Team | Predecessors
---+------+------+-------------
3  | C    | 2    | 1, 2
4  | D    | 2    | None

Therefore I use the following SQL-Query:

SELECT Tasks.*, GROUP_CONCAT(Predecessors.PredecessorID)
FROM Tasks LEFT JOIN Predecessors ON Tasks.ID = Predecessors.TaskID 
WHERE Tasks.Team = 2 GROUP BY Predecessors.TaskID

which returns:

ID | Task | Team | Predecessors
---+------+------+-------------
3  | C    | 2    | 1, 2

What can I do to get get the line with the None Value too?

Here is my test code:

# -*- coding: utf-8 -*-

import sqlite3


con = sqlite3.connect('test.db')
cur = con.cursor()

# Drop old tables if they already exits and create new ones. (For testing).
cur.execute("""DROP TABLE IF EXISTS Tasks""")
cur.execute("""DROP TABLE IF EXISTS Predecessors""")

# Create tables.
cur.execute("""CREATE TABLE Tasks (ID INTEGER PRIMARY KEY AUTOINCREMENT, 
               Task TEXT, Team INTEGER)""")
cur.execute("""CREATE TABLE Predecessors (ID INTEGER PRIMARY KEY AUTOINCREMENT,
               TaskID INTEGER, PredecessorID INTEGER)""")

# Insert some values.
sql = """INSERT INTO Tasks (Task, Team) VALUES (?, ?)"""
for task in [('A', 1), ('B', 1), ('C', 2), ('D', 3)]:
    cur.execute(sql, task)

sql = """INSERT INTO Predecessors (TaskID, PredecessorID) VALUES (?, ?)"""
for predecessor in [(1, None), (2, 1), (3, 1), (3, 2), (4, None)]:
    cur.execute(sql, predecessor)

con.commit()

sql = """SELECT Tasks.*, GROUP_CONCAT(Predecessors.PredecessorID)
FROM Tasks LEFT JOIN Predecessors ON Tasks.ID = Predecessors.TaskID 
WHERE Tasks.Team = 2 GROUP BY Predecessors.TaskID"""
cur.execute(sql)
data = cur.fetchall()
print data

con.close()

Thanks for help!!


Solution

  • The problem is the GROUP BY Predecessors.TaskID; for a row without matches, all Predecessors columns are NULL.

    Just use GROUP BY Tasks.ID instead.