如何在sqlite中简化查询布尔数据?

时间:2019-06-17 01:16:13

标签: c# sqlite

我有一个查询,它每天根据分配的字母代码来计算人员总数。

我用了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 个答案:

答案 0 :(得分:2)

SQL数据库都是关于在数据之间建立关系的模型,并且有建立良好的方法。在这种情况下,您有许多个用户,每个用户可能具有许多技能,即多对多关系many names已知对此建模的方法,但是我更喜欢 junction table 。基本上,不是使用每个技能都有一列,每个用户只有一行的表,而是有(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放在中间,可以将AttendanceSkillsAvailable表连接在一起:

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中非常复杂的过程-或闲置的列浪费了一些空间。它使设计变得脆弱,复杂。更好地发挥关系数据库的优势。