Как упростить запрос булевых данных в sqlite? - PullRequest
0 голосов
/ 17 июня 2019

У меня есть запрос, который подсчитывает численность персонала по присвоенному буквенному коду в день.

Я использовал 3 таблицы;

TABLE :status as st
+----------------+---------------+--------+
| ID | status_name | status_code | status |
+----+-------------+-------------+--------+
| 1  | Available   | A           | true   |
+------------------+-------------+--------+
| 2  | HalfDay     | H           | true   |
+------------------+-------------+--------+
| 3  | On Leave    | OL          | true   |            
+------------------+-------------+--------+
| 4  | Restday     | R           | true   |            
+------------------+-------------+--------+
| 5  | Vacation    | V           | true   |            
+------------------+-------------+--------+

TABLE : employees as e
+--------------+-------+-------+------+----------+
| EmployeeName | Site  | Shift | Team | JobTitle |
+--------------+-------+-------+------+----------+
| Steve        | Bldg1 | Night | N1   | Doctor   |
+--------------+-------+-------+------+----------+
| Dave         | Bldg1 | Night | N2   | Nurse    | 
+--------------+-------+-------+------+----------+
| Jack         | Bldg1 | Night | N2   | Nurse    |
+--------------+-------+-------+------+----------+
| Jacob        | Bldg2 | Day   | D1   | Doctor   |
+--------------+-------+-------+------+----------+
| Noah         | Bldg2 | Day   | D2   | Nurse    | 
+--------------+-------+-------+------+----------+
| MAX          | Bldg2 | Day   | D2   | Nurse    | 
+--------------+-------+-------+------+----------+

TABLE : schedule as sc
+----------+-------+-------+------+-----+-----+-----+-----+-----+-----+-----+
| JobsType | Site  | Shift | Team | SUN | MON | TUE | WED | THU | FRI | SAT |
+----------+-------+-------+------+-----+-----+-----+-----+-----+-----+-----+
| Doctor   | Bldg1 | Night | N1   | A   | H   | A   | A   | OL  | A   | A   |
+----------+-------+-------+------+-----+-----+-----+-----+-----+-----+-----+
| Nurse    | Bldg1 | Night | N2   | A   | H   | H   | A   | A   | A   | A   |
+----------+-------+-------+------+-----+-----+-----+-----+-----+-----+-----+
| Doctor   | Bldg2 | Day   | D1   | H   | A   | H   | H   | A   | A   | OL  |
+----------+-------+-------+------+-----+-----+-----+-----+-----+-----+-----+
| Nurse    | Bldg1 | Night | N2   | A   | H   | H   | A   | A   | A   | A   |
+----------+-------+-------+------+-----+-----+-----+-----+-----+-----+-----+

Используя этот запрос:

SELECT st.status_name, st.status_code
 , sum(sc.SUN = st.status_code) AS SUN
 , sum(sc.MON = st.status_code) AS MON
 , sum(sc.TUE = st.status_code) AS TUE
 , sum(sc.WED = st.status_code) AS WED
 , sum(sc.THU = st.status_code) AS THU
 , sum(sc.FRI = st.status_code) AS FRI
 , sum(sc.SAT = st.status_code) AS SAT
FROM status AS st
JOIN schedule AS sc ON st.status_code IN (sc.SUN, sc.MON, sc.TUE, sc.WED
                                        , sc.THU, sc.FRI, sc.SAT)
JOIN employees AS e ON sc.JobsType = e.JobTitle AND sc.Site = e.Site
                   AND sc.Shift = e.Shift AND sc.Team = e.Team
GROUP BY st.status_name, st.status_code
ORDER BY st.status_name, st.status_code;

Я достиг этого результата:

+--------------+-----+-----+-----+-----+-----+-----+-----+
| STATUS TYPES | SUN | MON | TUE | WED | THU | FRI | SAT |
+--------------+-----+-----+-----+-----+-----+-----+-----+
| Available    | 5   | 4   | 4   | 5   | 5   | 6   | 5   |
+--------------+-----+-----+-----+-----+-----+-----+-----+
| HalfDay      | 1   | 5   | 5   | 1   | 0   | 0   | 0   |
+--------------+-----+-----+-----+-----+-----+-----+-----+
| On Leave     | 0   | 0   | 0   | 0   | 1   | 0   | 1   |
+--------------+-----+-----+-----+-----+-----+-----+-----+
| Restday      | 0   | 0   | 0   | 0   | 0   | 0   | 0   |
+--------------+-----+-----+-----+-----+-----+-----+-----+
| Vacation     | 0   | 0   | 0   | 0   | 0   | 0   | 0   |
+--------------+-----+-----+-----+-----+-----+-----+-----+

----------------------------------------------- --------------------

Сейчас мне трудно работать с логическим значением для справки.

Вот мои таблицы;

TABLE: SkillList (1/0 = true/false)
+----------+--------+
| Skills   | Status |
+----------+--------+
| Skill_1  | 1      | 
+----------+--------+
| Skill_2  | 1      |
+----------+--------+
| Skill_3  | 1      | 
+----------+--------+
| Skill_4  | 1      |
+----------+--------+
| Skill_5  | 0      |
+----------+--------+

TABLE: Skill Available (1/0 = true/false)
+----------+--------+---------+---------+---------+
| Username | Skill_1| Skill_2 | Skill_3 | Skill_4 |
+----------+--------+---------+---------+---------+
| Steve    | 1      | 1       | 1       | 1       |
+----------+--------+---------+---------+---------+
| Dave     | 1      | 0       | 1       | 0       | 
+----------+--------+---------+---------+---------+
| Jack     | 1      | 1       | 0       | 0       | 
+----------+--------+---------+---------+---------+
| Jacob    | 1      | 1       | 0       | 0       | 
+----------+--------+---------+---------+---------+
Note: Zero represents users that doesn't have that skill.

TABLE: Attendance (1/0 = true/false)
+----------+-------+-------+-----+-----+-----+-----+-----+-----+-----+
| Username | Site  | Shift | SUN | MON | TUE | WED | THU | FRI | SAT |
+----------+-------+-------+-----+-----+-----+-----+-----+-----+-----+
| Steve    | Bldg1 | Night | 1   | 1   | 1   | 1   | 1   | 0   | 0   |
+----------+-------+-------+-----+-----+-----+-----+-----+-----+-----+
| Dave     | Bldg1 | Night | 1   | 1   | 0   | 0   | 1   | 1   | 1   |
+----------+-------+-------+-----+-----+-----+-----+-----+-----+-----+
| Jack     | Bldg2 | Day   | 1   | 1   | 1   | 0   | 0   | 1   | 1   |
+----------+-------+-------+-----+-----+-----+-----+-----+-----+-----+
| Jacob    | Bldg1 | Night | 1   | 0   | 0   | 1   | 1   | 1   | 1   |
+----------+-------+-------+-----+-----+-----+-----+-----+-----+-----+
Note: Zero represents restday.

Используя приведенные выше таблицы, как я мог достичь этого результата, который учитывал бы доступного пользователя в день на основе его навыка?

+-----------+-----+-----+-----+-----+-----+-----+-----+
| SkillList | SUN | MON | TUE | WED | THU | FRI | SAT |
+-----------+-----+-----+-----+-----+-----+-----+-----+
| Skill_1   | 4   | 3   | 2   | 2   | 3   | 3   | 3   |
+-----------+-----+-----+-----+-----+-----+-----+-----+
| Skill_2   | 3   | 3   | 1   | 1   | 2   | 2   | 2   |
+-----------+-----+-----+-----+-----+-----+-----+-----+
| Skill_3   | 2   | 2   | 1   | 0   | 2   | 1   | 1   |
+-----------+-----+-----+-----+-----+-----+-----+-----+
| Skill_4   | 1   | 1   | 0   | 0   | 1   | 0   | 0   |
+-----------+-----+-----+-----+-----+-----+-----+-----+
| Skill_5   | 0   | 0   | 0   | 0   | 0   | 0   | 0   |
+-----------+-----+-----+-----+-----+-----+-----+-----+

1 Ответ

2 голосов
/ 17 июня 2019

Базы данных SQL - все о моделировании отношений между данными, и для этого существуют хорошо разработанные способы. В этом случае у вас есть много пользователей, каждый из которых может иметь много навыков, - много ко многим . Способ моделирования этого известен под многими именами , но я предпочитаю соединительную таблицу . По сути, вместо таблицы со столбцом для каждого навыка и строкой для каждого пользователя, есть таблица из (skill id, user id) пар со строкой для каждой конкретной комбинации. Если у пользователя нет навыка, строка с этой конкретной комбинацией не существует.

Настройка некоторых примеров таблиц из ваших данных, чтобы продемонстрировать идею:

CREATE TABLE SkillList(id INTEGER PRIMARY KEY, skill TEXT);
INSERT INTO SkillList VALUES
  (1, 'Skill 1'), (2, 'Skill 2'), (3, 'Skill 3'), (4, 'Skill 4'), (5, 'Skill 5');

CREATE TABLE Attendance(id INTEGER PRIMARY KEY, username TEXT UNIQUE
                      , site TEXT, shift Text, SUN INTEGER, MON INTEGER
                      , TUE INTEGER, WED INTEGER, THU INTEGER, FRI INTEGER
                      , SAT INTEGER);
INSERT INTO Attendance VALUES
 (1, 'Steve', 'Bldg1', 'Night', 1, 1, 1, 1, 1, 0, 0),
 (2, 'Dave', 'Bldg1', 'Night', 1, 1, 0, 0, 1, 1, 1),
 (3, 'Jack', 'Bldg2', 'Day', 1, 1, 1, 0, 0, 1, 1),
 (4, 'Jacob', 'Bldg1', 'Night', 1, 0, 0, 1, 1, 1, 1);

CREATE TABLE SkillsAvailable(skill_id INTEGER REFERENCES SkillList(id)
                           , user_id INTEGER REFERENCES Attendance(id)
                           , PRIMARY KEY(skill_id, user_id)) WITHOUT ROWID;
INSERT INTO SkillsAvailable VALUES
 (1, 1), (1, 2), (1, 3), (1, 4),
 (2, 1), (2, 3), (2, 4),
 (3, 1), (3, 2),
 (4, 1);

позволит вам объединить таблицы SkillList и Attendance вместе, поставив SkillsAvailable в середине:

SELECT sl.skill AS "Skill Name"
     , ifnull(sum(a.SUN), 0) AS SUN
     , ifnull(sum(a.MON), 0) AS MON
     , ifnull(sum(a.TUE), 0) AS TUE
     , ifnull(sum(a.WED), 0) AS WED
     , ifnull(sum(a.THU), 0) AS THU
     , ifnull(sum(a.FRI), 0) AS FRI
     , ifnull(sum(a.SAT), 0) AS SAT
FROM SkillList AS sl
LEFT OUTER JOIN SkillsAvailable AS sa ON sl.id = sa.skill_id
LEFT OUTER JOIN Attendance AS a ON sa.user_id = a.id
GROUP BY sl.id
ORDER BY sl.skill;

Внешние объединения используются для того, чтобы навыки, которые никем не использовались, по-прежнему отображались в результатах:

Skill Name  SUN         MON         TUE         WED         THU         FRI         SAT
----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------
Skill 1     4           3           2           2           3           3           3
Skill 2     3           2           2           2           2           2           2
Skill 3     2           2           1           1           2           1           1
Skill 4     1           1           1           1           1           0           0
Skill 5     0           0           0           0           0           0           0

Помимо усложнения такого рода расчетов, у вашей текущей схемы базы данных есть и другие проблемы с таблицей "Skills Available" - добавление нового навыка означает добавление нового столбца, удаление навыка, который вам не нужен, означает либо удаление этого столбца - очень запутанный процесс в sqlite - или когда неиспользуемые зависают, тратя немного места. Это делает для хрупкого, над сложным дизайном. Лучше играть на сильных сторонах реляционных баз данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...