【问题标题】:SQL join 3 tables (based on 2 criterias?)SQL 连接 3 个表(基于 2 个条件?)
【发布时间】:2012-11-22 18:59:05
【问题描述】:

我有 3 个这样的表设置(有点简化):

时间跟踪:id、tr_proj_id、tr_min、tr_type
time_projects: id, project_name
time_tasks: id, task_name

基本上,我想根据 tr_type 检索 project_nametask_name,这可能是“项目”或“任务”的价值

一个例子

时间跟踪

+----+------------+--------+---------+
| id | tr_proj_id | tr_min | tr_type |
+----+------------+--------+---------+
|  1 |          3 |     60 | project |
|  2 |          3 |    360 | task    |
|  3 |          1 |    120 | project |
|  4 |          2 |     30 | project |
|  5 |          2 |     30 | task    |
|  6 |          1 |     90 | task    |
+----+------------+--------+---------+

time_projects

+----+------------------------+
| id |      project_name      |
+----+------------------------+
|  1 | Make someone happy     |
|  2 | Start a project        |
|  3 | Jump out of the window |
+----+------------------------+

time_tasks

+----+---------------------+
| id |      task_name      |
+----+---------------------+
|  1 | drink a beer        |
|  2 | drink a second beer |
|  3 | drink more          |
+----+---------------------+

期望的输出

+----+------------------------+------------+--------+---------+
| id |          name          | tr_proj_id | tr_min | tr_type |
+----+------------------------+------------+--------+---------+
|  1 | Jump out of the window |          3 |     60 | project |
|  2 | drink more             |          3 |    360 | task    |
|  3 | Make someone happy     |          1 |    120 | project |
|  4 | Start a project        |          2 |     30 | project |
|  5 | drink a second beer    |          2 |     30 | task    |
|  6 | drink a beer           |          1 |     90 | task    |
+----+------------------------+------------+--------+---------+

在整个 JOIN 事情上真的很糟糕,这是我迄今为止唯一想到的(这不起作用..):

SELECT tt.tr_proj_id, tt.tr_type, tt.tr_min, pp.project_name, pp.id, ta.task_name, ta.id
FROM time_tracking as tt, time_projects as pp, time_tasks as ta 
WHERE ((tt.tr_type = 'project' AND pp.id = tt.tr_proj_id) OR (tt.tr_type = 'task' AND ta.id = tt.tr_proj_id)) 
AND tt.tr_min > 0
ORDER BY tt.tr_proj_id DESC

如果有人知道如何做到这一点,请随时分享!


更新:我好像忘了指明我使用的是访问数据库。这显然不接受CASEcoalesce 之类的东西。显然有IIF(),但我不太确定在这种情况下如何使用它。

【问题讨论】:

  • 为什么这是任务? 2 | drink more | 3 | 360 | task
  • 所需的输出无法理解,“发送电子邮件”在哪里?
  • @HamletHakobyan 我的错,你是对的,我编辑以更正输出
  • 更新了我的问题,忘了说我在这种情况下使用的是访问数据库

标签: sql ms-access join


【解决方案1】:

使用 join 子句并将连接条件从 where 子句移到 on 子句中:

SELECT
    tt.tr_proj_id,
    tt.tr_type,
    tt.tr_min,
    pp.project_name,
    pp.id,
    ta.task_name,
    ta.id
FROM time_tracking as tt
left join time_projects as pp on tt.tr_type = 'project' AND pp.id = tt.tr_proj_id
left join time_tasks as ta on tt.tr_type = 'task' AND ta.id = tt.tr_proj_id
WHERE tt.tr_min > 0
ORDER BY tt.tr_proj_id DESC,tt.tr_day ASC

我使用了left join,它会在主表中为您提供一行,即使连接不存在(如果没有连接,您会从连接表中的列中获得空值)


这里有一个关键点,许多 SQL 程序员没有意识到,ON 子句可能包含任何条件,甚至不是来自连接表的条件(如本例所示)。许多程序员认为条件只能是与正式外键关系相关的条件。

【讨论】:

    【解决方案2】:

    试试这个:

    SELECT
        tt.id,
        CASE WHEN tt.tr_type = 'project' THEN pp.project_name
             WHEN tt.tr_type = 'task' THEN ta.task_name END as name,
        tt.tr_proj_id,
        tt.tr_type,
        tt.tr_min,
    FROM time_tracking as tt
       left join time_projects as pp on pp.id = tt.tr_proj_id
       left join time_tasks as ta on ta.id = tt.tr_proj_id
    WHERE tt.tr_min > 0
    ORDER BY tt.tr_proj_id DESC
    

    【讨论】:

    • 在这种情况下使用 Access,我将 CASE 替换为 IIf(),它成功了! SELECT tt.id, IIf([tt.tr_type] = 'project', [pp.project_name],[ta.task_name]) as name, tt.tr_proj_id, etc..
    【解决方案3】:

    对两个连接执行联合:

    select tt.id, tp.project_name name, tt.tr_proj_id, tt.tr_min, tt.tr_type
      from time_tracking tt
           inner join time_projects tp on tp.id = tt.tr_proj_id
     where tt.tr_type = 'project'
    union all
    select tt.id, tp.project_name name, tt.tr_proj_id, tt.tr_min, tt.tr_type
      from time_tracking tt
           inner join time_tasks tk on tk.id = tt.tr_proj_id
     where tt.tr_type = 'task'
    

    这将为您提供所需的确切表格结果

    【讨论】:

      【解决方案4】:
      SELECT
          time_tracking.id,
          time_tracking.tr_min,
          time_tracking.tr_type,
          coalesce(time_projects.project_name, time_tasks.task_name) as name
      FROM time_tracking
      LEFT OUTER JOIN time_projects on time_projects.id = time_tracking.tr_proj_id AND time_tracking.tr_type = 'project'
      LEFT OUTER JOIN time_tasks on time_tasks.id = time_tracking.tr_proj_id AND time_tracking.tr_type = 'task'
      WHERE time_tracking.tr_min > 0
      ORDER BY time_tracking.id DESC -- ...
      

      coalesce 是 MSSQL,在其他数据库技术中有等价的 ISNULL

      这个想法是你加入表,如果加入失败,你会得到NULL 加入失败的地方。然后你使用COALESCE 来挑选出成功加入的值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-23
        • 1970-01-01
        • 2012-02-22
        • 1970-01-01
        相关资源
        最近更新 更多