如何使用生成多行的select语句更新表?

时间:2013-06-06 07:13:32

标签: sql sql-server tsql sql-update

我有两张桌子:

[Table container]
id int
<some more fields>
latest_measurement int

[Table measurement]
id int
container_id int
unixtime bigint

现在,我想根据测量表中的最新测量值更新传感器表latest_measurement列。我准备了子查询以返回每sensor_id的最新测量值,这有效:

SELECT m.fill_level
from measurement m
inner join (
    select m.container_id, MAX(m.unixtime) as maxdate from measurement m GROUP BY container_id
) m2
on m2.container_id = m.container_id
where m.unixtime = m2.maxdate

但是,如果我在我的更新语句中使用此查询,如下所示,它将失败并出现异常:

UPDATE container
SET latest_fill_level = (
    SELECT m.fill_level
    from measurement m
    inner join (
        select m.container_id, MAX(m.unixtime) as maxdate from measurement m GROUP BY container_id
) m2
    on m2.container_id = m.container_id
    where m.unixtime = m2.maxdate
    and container.id = m.container_id)

最后,这是例外:

Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

如何编写一个更新语句,该语句可以从产生多个值的SELECT语句中使用各自的值更新多行?

1 个答案:

答案 0 :(得分:2)

您的子查询不会破坏关系。如果使用最新的unixtime进行多次测量,则会返回多行。由于SQL Server无法知道应该使用哪一行来更新列,因此会引发Subquery returned more than 1 value.错误。

您可以使用row_number()打破关系:

update  c
set     latest_measurement = m.fill_level
from    container c
join    (
        select  row_number() over (
                    partition by container_id
                    order by unixtime desc) as rn
        ,       *
        from    measurement
        ) m
on      c.id = m.container_id
        and m.rn = 1 -- Latest measurement only

或者,您可以使用top 1子句打破关系:

update  container
set     latest_measurement = 
        (
        select  top 1 fill_level
        from    measurement m
        where   container.id = m.container_id
        order by
                unixtime desc
        )