【问题标题】:SQlite join same table twice with different "on" statementSQlite 使用不同的“on”语句将同一个表连接两次
【发布时间】:2012-11-28 17:36:13
【问题描述】:

我找不到我的问题的答案,我不知道我的查询是否正确,这可能是 SQLite 问题,请帮我解决问题。

我的数据库中有两个表:

processTable {id}
taskTable {id, processId, amount, done}

存在多对一关系(一个进程可以分配多个任务)。 “数量”和“完成”是提供任务进度信息的整数值。如果 "done" >= "amount",则任务完成。我需要查询数据库以获得类似的东西:

+---------+-----------+------------+
| process | tasksDone | tasksCount |
+---------+-----------+------------+
| 1       | 1         | 3          |
+---------+-----------+------------+
| 2       | 2         | 5          |
+---------+-----------+------------+

根据我的表格中的数据:

processTable
+----+
| id |
+----+
| 1  |
+----+
| 2  |
+----+

tasksTable
+----+-----------+--------+------+
| id | processId | amount | done |
+----+-----------+--------+------+
| 1  | 1         | 10     | 10   | <- this task is done
+----+-----------+--------+------+
| 2  | 1         | 15     | 5    |
+----+-----------+--------+------+
| 3  | 1         | 80     | 5    |
+----+-----------+--------+------+
| 4  | 2         | 25     | 0    |
+----+-----------+--------+------+
| 5  | 2         | 60     | 60   | <- this task is done
+----+-----------+--------+------+
| 6  | 2         | 30     | 15   |
+----+-----------+--------+------+
| 7  | 2         | 40     | 40   | <- this task is done
+----+-----------+--------+------+
| 8  | 2         | 100    | 50   |
+----+-----------+--------+------+

所以,我写了这个查询:

SELECT processTable.id AS process, 
       COUNT(tasksTableDone.id) AS tasksDone, 
       COUNT(tasksTableAll.id) AS tasksCount 

FROM processTable

LEFT JOIN tasksTable AS tasksTableAll 
     ON   tasksTableAll.processId = processTable.id 

LEFT JOIN tasksTable AS tasksTableDone 
     ON   tasksTableDone.processId = processTable.id 
          AND
          tasksTableDone.done >= tasksTableDone.amount 

但我得到的是:

+---------+-----------+------------+
| process | tasksDone | tasksCount |
+---------+-----------+------------+
| 1       | 3         | 3          |
+---------+-----------+------------+
| 2       | 5         | 5          |
+---------+-----------+------------+

我尝试一次只使用一个联接来运行查询,并且一切运行良好。

只有第一次加入的查询:

SELECT processTable.id AS process,  
       COUNT(tasksTableAll.id) AS tasksCount 

FROM processTable

LEFT JOIN tasksTable AS tasksTableAll 
     ON   tasksTableAll.processId = processTable.id 

Result:
+---------+------------+
| process | tasksCount |
+---------+------------+
| 1       | 3          |
+---------+------------+
| 2       | 5          |
+---------+------------+

仅使用第二个连接查询:

SELECT processTable.id AS process,  
       COUNT(tasksTableDone.id) AS tasksDone 

FROM processTable

LEFT JOIN tasksTable AS tasksTableDone 
     ON   tasksTableDone.processId = processTable.id 
          AND
          tasksTableDone.done >= tasksTableDone.amount 

Result:
+---------+-----------+
| process | tasksDone |
+---------+-----------+
| 1       | 1         |
+---------+-----------+
| 2       | 2         |
+---------+-----------+

如何在一个查询中使用这两个连接来获得正确的结果?我知道我可以使用另一个 SELECT 而不是 JOIN,但我认为它在性能方面会更昂贵。

【问题讨论】:

    标签: sql sqlite join


    【解决方案1】:

    您可以使用聚合实现CASE 语句:

    使用SUM()的版本

    SELECT p.id AS process,  
      sum(case when t.amount = t.done then 1 else 0 end) AS tasksDone,
      count(p.id) AS tasksCount
    FROM processTable p
    LEFT JOIN tasksTable t
      ON t.processId = p.id 
    group by p.id
    

    SQL Fiddle with Demo

    使用COUNT()的版本:

    SELECT p.id AS process,  
      count(case when t.amount = t.done then 1 else null end) AS tasksDone,
      count(p.id) AS tasksCount
    FROM processTable p
    LEFT JOIN tasksTable t
      ON t.processId = p.id 
    group by p.id
    

    SQL Fiddle with Demo

    编辑,在您发表评论后,您可以将其包装在一个选择中以获得progress

    select process,
      tasksDone,
      tasksCount,
      (tasksDone / tasksCount) progress
    from
    (
      SELECT p.id AS process,  
        count(case when t.amount = t.done then 1 else null end) AS tasksDone,
        count(p.id) AS tasksCount
      FROM processTable p
      LEFT JOIN tasksTable t
        ON t.processId = p.id 
      group by p.id
    ) src
    

    【讨论】:

    • 您可以使用 TRUE=1 和 FALSE=0 的 SQLite/MySQL 功能。因此sum(case when t.amount = t.done then 1 else 0 end)sum(t.amount = t.done) 相同
    • @ypercube 谢谢你的信息,我不知道。我通常不在 MySQL 或 SQLite 中工作。
    • 这太棒了!它就像一个魅力,但还有一个问题:由于您不使用 JOIN,因此您无法添加包含计算进度值的另一列,例如:SELECT ... (tasksDone / tasksCount) AS progress - 该问题的任何解决方案?
    • @Darrarski 查看我的编辑,您可以将查询包装在另一个 select 中以轻松计算 progress。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-26
    • 1970-01-01
    • 2011-11-12
    • 1970-01-01
    • 1970-01-01
    • 2020-09-15
    相关资源
    最近更新 更多