联合的嵌套查询和分组(SQL)

时间:2012-05-15 20:49:13

标签: mysql 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

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

7 个答案:

答案 0 :(得分: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

将结果放入派生的临时表中,您可以根据需要为列命名,但您使用的第一个名称仍然存在。

答案 1 :(得分:2)

我的解决方案将联合放在一个子查询中,然后由它们命令。您只需要第一行,因此您需要一个limit子句(或Oracle中的rownum = 1或MSSQL中的top 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

为了简化查询,我还删除了最里面的连接到工具。

答案 2 :(得分: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,但您希望按其他列排序。

答案 3 :(得分: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

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

答案 4 :(得分: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

答案 5 :(得分: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

答案 6 :(得分:0)

选择people.id为person_id,people.name为person_name,tools.name为toolsname 从table_people人们离开加入 ( 选择       例如,在installation_date> delivery_date然后是act2.tool_id时                  else act1.tool_id以recent_most_tool_id结尾,       例如,在installation_date> delivery_date然后是act2.person_id                  否则act1.person_id以recent_most_person_id结尾     from table_activity1 act1 inner join table_activity2 act2          在act1.person_id = act2.person_id)X on people.id = X.recent_most_person_id 内连接table_tools工具 on tools.id = X.recent_most_tool_id