2012-05-15 66 views
3

我需要帮助编写查询以获取一些信息,但我在编写它时遇到困难。通过联合嵌套查询和分组(SQL)

[table_People] 
int id 
var name 

[table_Tools] 
int id 
var name 

[table_Activity1] 
int person_id 
int tool_id 
date delivery_date 

[table_Activity2] 
int person_id 
int tool_id 
date installation_date 

查询需要返回所有的人的名单,他们在任何活动1或2(两者之间发生的最近期的活动)最近使用的工具的名称。

SELECT 
    people.id AS personId, 
    people.name AS personName, 
    (
     SELECT 
      tools.name AS toolName 
     FROM 
      activity1 
     JOIN 
      tools ON tools.id=activity1.tool_id 
     WHERE 
      activity1.id=people.id 
     UNION ALL 
     SELECT 
      tools.name AS toolName 
     FROM 
      activity2 
     JOIN 
      tools ON tools.id=activity2.tool_id 
     WHERE 
      activity2.id=people.id 
     ORDER BY 
      installationDate,deliveryDate 
    ) AS toolName 
FROM 
    people 
ORDER BY 
    people.name 
ASC 

我遇到的问题是我无法按日期排序(发送或安装),因为我收到错误,因为它们是不同的列名称。

+3

由于子查询返回多个行,因此提供的查询不应起作用。 – nawfal

+0

“Activity1”和“Activity2”的主键是什么? –

回答

0

如果没有在select之后指定列,则无法对列进行排序。

例如:

select name from people order by name 

select a1.delivery_date, t.name from activity1 a1, tools t 
order by a1.delivery_date,t.name 

用于投影的所有选定的列必须在order by定义被定义为好。在你的例子中,两条select语句只是取tools.name as toolname,但你想按其他列排序。

+0

我不能“选择a1.delivery_date,t.name”,因为它嵌套在一个更大的选择投影为“(select a1.delivery_date,t.name ...)AS toolName。我不能选择2件事,然后只问一个工具名称 – user781439

0

SELECT 
    people.id AS personId, 
    people.name AS personName, 
    IF (
     (SELECT 
      deliveryDate AS dDate 
     FROM 
      activity1 
     WHERE 
      person_id=personId) --assuming you have only one row returned here, else limit by some condition 
     > 
     (SELECT 
      installationDate AS iDate 
     FROM 
      activity2 
     WHERE 
      person_id=personId) --assuming you have only one row returned here, else limit by some condition 
     , (SELECT 
       tools.name AS toolName 
      FROM 
       activity1 
      JOIN 
       tools ON tools.id=activity1.tool_id 
      WHERE 
       activity1.person_id=personId) 
     , (SELECT 
       tools.name AS toolName 
      FROM 
       activity2 
      JOIN 
       tools ON tools.id=activity2.tool_id 
      WHERE 
       activity2.person_id=personId) 
      ) AS toolName 
FROM 
    people   
ORDER BY 
    people.name 
ASC 

这个查询假设有在活动表每人只记录。如果还有更多,你需要根据总和最大条件限制你选择的结果集,或者只有你知道。

2

我的解决方案将联合放在一个子查询中,然后通过它们进行排序。您只需要在第一行,所以你需要(在MSSQL或ROWNUM = 1 Oracle或顶部1)限制条款:

SELECT people.id AS personId, 
     people.name AS personName, 
     (SELECT toolname 
     FROM ((SELECT tools.name AS toolName, delivery_date as thedate 
       FROM activity1 a 
       WHERE a.PersonId = people.id 
      ) union all 
       (SELECT tools.name AS toolName, installation_date as thedate 
       FROM activity2 a 
       WHERE a.PersonId = people.id 
      ) 
      ) a join 
      tools t 
      on a.toolsid = t.toolsid 
     order by 2 desc 
     limit 1 
     ) AS toolName 
FROM people 
ORDER BY people.name ASC 

为了简化查询,我也去掉了最里面的加盟工具。

+0

不工作,谢谢。 – user781439

+0

+1,这是我在这里找到的最佳解决方案,思考问题 – nawfal

0

MySQL版本(可能是你可以从它那里得到更紧凑的代码):

Select * from 
(
    Select toolName, person_id, Max(TargetDate) as MaxDate 
    From 
     (
      SELECT tools.name AS toolName, activity1.person_id, activity1.delivery_date as targetDate 
      FROM 
       activity1 
      JOIN 
       tools ON tools.id=activity1.tool_id 
      UNION ALL 
      SELECT 
       tools.name AS toolName, activity2.person_id, activity2.installation_date as TargetDate 
      FROM 
       activity2 
      JOIN 
       tools ON tools.id=activity2.tool_id 
     ) 
Group by toolName, person_id 

) preselect 
    join 
    (
    Select toolName, person_id, Max(TargetDate) 
    From 
      (
       SELECT tools.name AS toolName, activity1.person_id, activity1.delivery_date as targetDate 
       FROM 
        activity1 
       JOIN 
        tools ON tools.id=activity1.tool_id 
       UNION ALL 
       SELECT 
        tools.name AS toolName, activity2.person_id, activity2.installation_date as TargetDate 
       FROM 
        activity2 
       JOIN 
        tools ON tools.id=activity2.tool_id 
      )) result on result.toolName = preselect.toolName and result.person_id = preselect.person_id and result.TargetDate = preselect.MaxDate 
+0

使用MySQL作为标记。 – user781439

4

在子查询中使用UNION创建一个派生临时表。未选中的列不在结果集中,因此您不能对不在SELECT子句中的列进行ORDER。

当使用UNION时,在SELECT子句中使用的第一个列名在结果集中使用(类似于别名,尽管您也可以使用别名)。

只要确保在SELECT子句中命名该列即可。

你还需要一个LIMIT子句的子查询限制为单行:

SELECT 
    people.id AS personId, 
    people.name AS personName, 
    (
     SELECT 
      tools.name AS toolName, delivery_date 
     FROM 
      activity1 
     JOIN 
      tools ON tools.id=activity1.tool_id 
     WHERE 
      activity1.id=people.id 
     UNION ALL 
     SELECT 
      tools.name AS toolName, installation_date 
     FROM 
      activity2 
     JOIN 
      tools ON tools.id=activity2.tool_id 
     WHERE 
      activity2.id=people.id 
     ORDER BY 
      deliveryDate 
     LIMIT 1 
    ) AS toolName 
FROM 
    people 
ORDER BY 
    people.name 
ASC 

这里有一个更简单的例子来说明这个问题:

SELECT fish FROM sea 
UNION 
SELECT dog FROM land 
ORDER BY fish 

是一样的:

SELECT fish AS animal FROM sea 
UNION 
SELECT dog AS animal FROM land 
ORDER BY animal 

结果放入派生临时表中,您可以根据需要命名列,但是你使用棍子的第一个名字。

0
SELECT 
    p.id    AS person_id 
    , p.name   AS person_name 
    , CASE WHEN COALESCE(a1.delivery_date, '1000-01-01') 
       > COALESCE(a2.installation_date, '1000-01-01') 
      THEN t1.name 
      ELSE t2.name 
    END    AS tool_name 
FROM 
    People AS p 
    LEFT JOIN 
    Activity1 AS a1 
     ON (a1.tool_id, a1.delivery_date) = 
      (SELECT tool_id, delivery_date 
      FROM Activity1 AS a 
      WHERE a.person_id = p.id 
      ORDER BY delivery_date DESC 
      LIMIT 1 
      ) 
    LEFT JOIN 
    Tools AS t1 
     ON t1.id = a1.tool_id 
    LEFT JOIN 
    Activity2 AS a2 
     ON (a2.tool_id, a2.installation_date) = 
      (SELECT tool_id, installation_date 
      FROM Activity2 AS a 
      WHERE a.person_id = p.id 
      ORDER BY installation_date DESC 
      LIMIT 1 
      ) 
    LEFT JOIN 
    Tools AS t2 
     ON t2.id = a2.tool_id 
0

选择people.id如为person_id,people.name为PERSON_NAME,tools.name作为toolsname 从table_people人们留下加入 ( 选择 情况下INSTALLATION_DATE> DELIVERY_DATE然后act2.tool_id 其他act1.tool_id结束,因为recent_most_tool_id, 情况下,当INSTALLATION_DATE> DELIVERY_DATE然后act2.person_id 别的act1.person_id端从table_activity1 ACT1 recent_most_person_id 内上people.id = X.recent_mo加入table_activity2 ACT2 上act1.person_id = act2.person_id)X st_person_id 内部连接table_tools工具 on tools.id = X.recent_most_tool_id