3

我需要帮助编写查询以获取一些信息,但我无法编写它。

[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

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

4

7 回答 7

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

结果被放入一个派生的临时表中,您可以随意命名列,但您使用的第一个名称会保留。

于 2012-05-15T21:42:31.380 回答
2

我的解决方案将联合放在一个子查询中,然后按它们排序。您只需要第一行,因此您需要一个限制子句(或在 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

为了简化查询,我还删除了工具的最内层连接。

于 2012-05-15T21:13:59.043 回答
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
于 2012-05-15T22:05:54.347 回答
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

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

于 2012-05-15T21:10:04.787 回答
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但您想按其他列排序。

于 2012-05-15T20:59:31.377 回答
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
于 2012-05-15T21:21:16.090 回答
0

选择 people.id 作为 person_id,people.name 作为 person_name,tools.name 作为来自 table_people 的工具名 人们离开加入(选择安装日期>交付日期然后 act2.tool_id 的情况,否则 act1.tool_id 结束为最近的_工具_id,安装日期>交付日期的情况,然后是 act2。 person_id else act1.person_id end as recent_most_person_id from table_activity1 act1 内部连接 ​​table_activity2 act2 on act1.person_id=act2.person_id)X on people.id=X.recent_most_person_id 内部连接 ​​table_tools tools.id=X.recent_most_tool_id

于 2012-05-16T04:27:14.127 回答