Reputation: 579
I'm trying to do something very simple but can't figure out how.
Say I have this table called "Tasks" where each task has a chosen set of users that should carry it out. The numbers in the Users column refer to the ID column of the "Users" table.
Tasks table:
+--------------+-------------+--------------+
| Task | Created_On | Users |
+--------------+-------------+--------------+
| Task A | 19/11/22 | 1,3,4 |
| Task B | 19/11/22 | 1,4,5,6 |
| Task C | 19/11/22 | 2,3,6 |
+--------------+-------------+--------------+
Users table:
+--------------+-------------+
| ID | User |
+--------------+-------------+
| 1 | George |
| 2 | John |
| 3 | Jim |
| 4 | James |
| 5 | Jill |
| 6 | Joe |
+--------------+-------------+
How do you create the "Users" column of the Tasks table? There's no "Array" column type in Oracle.
Upvotes: 0
Views: 86
Reputation: 7801
As the answer is already accepted here is an option that could be used to insert data into bridging table from MTO's answer. SQL MODEL clause is used here:
SELECT t.TASK, t.CREATED_ON, t.USERS, t.IDS_COUNT, t.IDX "ID_NO", t.ID, u.USER_NAME
FROM ( Select *
From ( Select TASK, CAST(0 As VarChar2(32)) "ID", USERS, CREATED_ON,
Coalesce(Length(USERS) - Length(Replace(USERS,',',null)), Length(USERS), 0) + 1 "IDS_COUNT"
From tasks
)
MODEL
PARTITION BY (TASK)
DIMENSION BY (0 "IDX")
MEASURES (USERS, CREATED_ON, IDS_COUNT, ID)
RULES ITERATE(6) -- declare bigger number than expected number of elements in list
(
USERS[ITERATION_NUMBER] = USERS[0], CREATED_ON[ANY] = CREATED_ON[0], IDS_COUNT[ANY] = IDS_COUNT[0],
ID[ITERATION_NUMBER] = CASE
WHEN ITERATION_NUMBER BETWEEN 1 And IDS_COUNT[0]
THEN SubStr(SubStr(',' || USERS[0] || ',', InStr(',' || USERS[0] || ',', ',', 1, ITERATION_NUMBER)+1), 1, InStr(',' || USERS[0] || ',', ',', 1, ITERATION_NUMBER+1) - InStr(',' || USERS[0] || ',', ',', 1, ITERATION_NUMBER) - 1)
END
)
) t
INNER JOIN users u ON(u.ID = t.ID) --LEFT JOIN if you want to see possible unmatched IDs - USER_NAME would be Null
Where IDX Between 1 And IDS_COUNT
Order By TASK, IDX
Result:
TASK | CREATED_ON | USERS | IDS_COUNT | ID_NO | ID | USER_NAME |
---|---|---|---|---|---|---|
Task A | 19-NOV-22 | 1,3,4 | 3 | 1 | 1 | George |
Task A | 19-NOV-22 | 1,3,4 | 3 | 2 | 3 | Jim |
Task A | 19-NOV-22 | 1,3,4 | 3 | 3 | 4 | James |
Task B | 19-NOV-22 | 1,4,5,6 | 4 | 1 | 1 | George |
Task B | 19-NOV-22 | 1,4,5,6 | 4 | 2 | 4 | James |
Task B | 19-NOV-22 | 1,4,5,6 | 4 | 3 | 5 | Jill |
Task B | 19-NOV-22 | 1,4,5,6 | 4 | 4 | 6 | Joe |
Task C | 19-NOV-22 | 2,3,6 | 3 | 1 | 2 | John |
Task C | 19-NOV-22 | 2,3,6 | 3 | 2 | 3 | Jim |
Task C | 19-NOV-22 | 2,3,6 | 3 | 3 | 6 | Joe |
Regards...
Upvotes: 0
Reputation: 142798
There's no "Array" column type in Oracle
Right, but there's another built-in datatype you could use - sys.odcinumberlist
. Here's how:
SQL> create table task (task varchar2(10), created_on date, users sys.odcinumberlist);
Table created.
SQL> insert into task (task, created_on, users)
2 values ('Task A', date '2022-11-19', sys.odcinumberlist(1,3,4));
1 row created.
SQL> select * from task;
TASK CREATED_ON USERS
---------- ---------- ----------------------------------------
Task A 19.11.2022 ODCINUMBERLIST(1, 3, 4)
SQL>
So, which users are these 1, 3 and 4?
SQL> select * from users;
ID USERNAME
---------- ----------
1 George --> this
2 John
3 Jim --> this
4 James --> this
5 Jill
6 Joe
6 rows selected.
SQL> select t.task, u.username
2 from task t join users u on u.id in (select * From table(t.users));
TASK USERNAME
---------- ----------
Task A George
Task A Jim
Task A James
SQL>
Upvotes: 1
Reputation: 168137
Create a bridging table:
CREATE TABLE task_users (
Task CONSTRAINT task_users__task__fk REFERENCES tasks (task),
User_id CONSTRAINT task_users__user_id__fk REFERENCES users (id),
CONSTRAINT task_users__task__user_id__pk PRIMARY KEY(task, user_id)
);
Then you can insert the data:
INSERT INTO task_users (task, user_id)
SELECT 'Task A', 1 FROM DUAL UNION ALL
SELECT 'Task A', 3 FROM DUAL UNION ALL
SELECT 'Task A', 4 FROM DUAL UNION ALL
SELECT 'Task B', 1 FROM DUAL UNION ALL
SELECT 'Task B', 4 FROM DUAL UNION ALL
SELECT 'Task B', 5 FROM DUAL UNION ALL
SELECT 'Task B', 6 FROM DUAL UNION ALL
SELECT 'Task C', 2 FROM DUAL UNION ALL
SELECT 'Task C', 3 FROM DUAL UNION ALL
SELECT 'Task C', 6 FROM DUAL;
and the table is constrained to only contain valid users and unique task/user pairs.
Upvotes: 4