SQL内部查询在更新查询中返回多个值

SQL内部查询在更新查询中返回多个值,sql,sql-server,sql-update,inner-query,Sql,Sql Server,Sql Update,Inner Query,我有一个表要使用另一个表的记录进行更新,我这样做是为了将信息从一个系统(数据库)带到另一个系统。 场景有点复杂,但我急需帮助:-s 共有3个表-组件、扫描和阶段链接 组件 component_id stage_id ------------ -------- 1 NULL 2 NULL 3 NULL 4 NULL 5 NULL 扫描 scan_id compo

我有一个表要使用另一个表的记录进行更新,我这样做是为了将信息从一个系统(数据库)带到另一个系统。 场景有点复杂,但我急需帮助
:-s

共有3个表-
组件
扫描
阶段链接

组件

component_id  stage_id
------------  --------
1              NULL
2              NULL
3              NULL
4              NULL
5              NULL
扫描

scan_id  component_id  scanner_id           date_scanned
-------  ------------  ----------  -----------------------
 1         1           scanner_a    2012-01-01 07:25:15.125
 2         1           scanner_b    2012-01-02 08:14:05.456
 3         2           scanner_a    2012-01-01 12:05:45.465
 4         3           scanner_a    2012-01-01 19:45:12.536
 5         1           scanner_c    2012-01-03 23:33:54.243
 6         2           scanner_b    2012-01-02 11:59:12.545
舞台链接

stage_link_id  scanner_id  stage_id
    -------     ----------  ----------  
       1         scanner_a    1   
       2         scanner_b    1    
       3         scanner_c    2    
       4         scanner_d    2    
       5         scanner_e    2   
       6         scanner_f    3  
我需要根据最新扫描
更新
表格
组件
设置
字段
阶段id
。每次扫描都会根据所涉及的扫描仪将组件带到一个阶段。我编写以下查询是为了
更新
组件
,但它抛出一个错误:

子查询返回了多个值。当子查询紧跟在“=”之后时,这是不允许的。

查询是

UPDATE component
SET stage_id = (select stage_id
                from(
                    select scn.scanner_id, sl.stage_id
                    from scan scn
                    INNER JOIN stage_link sl ON scn.scanner_id = sl.scanner_id
                    where scn.date_scanned = (  select temp_a.max_date 
                                                from (  SELECT x.component_id, MAX(x.date_scanned) as max_date
                                                        FROM scan x
                                                        where component_id = x.component_id 
                                                        GROUP BY x.component_id
                                                      ) as temp_a
                                                where component_id = temp_a.component_id)
                    ) as temp_b
                )
我正在使用
mssqlserver
并希望使用no
PHP
或任何其他语言来解决这个问题

我已经试了一天来让这项工作,但仍然没有办法让这项工作。任何帮助都将不胜感激


非常感谢:-)

嗯,您的子查询返回了多个值。一种简单的方法是进行聚合:

SET stage_id = (select max(stage_id)
. . .
一个可能的原因是最近的日期有多个扫描。鉴于上下文,您只能选择一个,那么最小值或最大值就足够了

然而,我认为真正的原因是,您没有相关子查询的正确别名。我认为这句话:

where component_id = x.component_id
where component_id = temp_a.component_id
应包括别名,可能是:

where component.component_id = x.component_id
where component.component_id = temp_a.component_id
如果这还不够,你需要解释你想要什么。是否希望查询返回最近日期的随机扫描?是否要在最近的日期更新所有扫描的组件

你需要进一步调查。试着这样做:

select scn.scanner_id, sl.stage_id, count(*)
from scan scn INNER JOIN
     stage_link sl
     ON scn.scanner_id = sl.scanner_id join
     (SELECT x.component_id,
             MAX(x.date_scanned) as max_date
      FROM scan x
      GROUP BY x.component_id
     ) cmax
     on scn.component_id = cmax.component_id
where scn.date_scanned = cmax.maxdate 
group by scn.scanner_id, sl.stage_id
order by count(*) desc

这需要OLAP功能才能工作:

UPDATE Component SET Component.stage_id = Stage_Link.stage_id
FROM Component
JOIN (SELECT component_id, scanner_id, 
             ROW_NUMBER() OVER(PARTITION BY component_id 
                               ORDER BY date_scanned DESC) rownum
      FROM Scan) Scan
  ON Scan.component_id = Component.component_id
     AND Scan.rownum = 1
JOIN Stage_Link
  ON Stage_Link.scanner_id = Scan.scanner_id
WHERE Component.stage_id IS NULL
这将生成以下结果集:

Component
component_id   stage_id
========================
1              2
2              1
3              1
4              null
5              null

(我还有一个可用的SQL FIDLE。)

在不使用相关子查询的情况下检查此项:

UPDATE  Com
SET     stage_id = Temp4.stage_id
FROM    dbo.component Com
        INNER JOIN 
        ( 
            SELECT Temp2.component_id ,SL.stage_id
            FROM   dbo.stage_link SL
            INNER JOIN (
                            SELECT component_id ,scanner_id
                            FROM   scan
                            WHERE  date_scanned IN (
                                SELECT  MaxScanDate
                                FROM    
                                ( 
                                    SELECT component_id , MAX(date_scanned) MaxScanDate
                                    FROM scan
                                    GROUP BY component_id
                                ) Temp 
                            )
                        ) Temp2 ON Temp2.scanner_id = SL.scanner_id
        ) Temp4 ON Com.component_id = Temp4.component_id
输出:

component_id stage_id
------------ -----------
1            2
2            1
3            1
4            NULL
5            NULL

非常感谢你的回答!!我试图通过查看每次对一个组件进行的扫描来更新表
component
中的所有组件。因此,当
组件分组时,
max
日期只能进行一次扫描。你建议的问题是信息的准确性。而且
stage\u id
的最大数值不是组件可能的最新阶段(很抱歉,这种情况非常复杂!)我的问题是,每个组件在
max
日期只能进行一次扫描,它仍然返回多个1:-(@mithilatw…将子查询从更新中取出,并开始调查重复出现的位置。根据扫描程序id或组件,它可能是其中一个表中的重复项。但经验表明,同一日期的重复项很可能是罪魁祸首。尝试了此方法后,无效。应该有比使用相关su更好的方法B查询。非常感谢您的时间!我在我的数据库中尝试了这个建议,查询运行了1个多小时,但仍然没有返回结果。我看到您尝试实施的想法,我非常同意。我不明白为什么我的数据库不接受它:-P#winces#事实上,您的问题是您的数据库确实接受了它-这是错误的只是没有尽可能快地运行。它可能正在为每一行运行值检索。当它很小(如测试数据)时,这不是一个问题,但显然不能很好地扩展。SQL Server不支持
UPDATE
语句中的CTE吗?您可以尝试至少获取
行数()的部分
导入CTE,使其只运行一次(这可能是最好的节约)。或者,将子选择的结果转储到一个临时表中,并从该表运行相关更新。@X-Zero:我认为您指的是相关子查询而不是CTE。SQL Server支持两者,但如您所述,对于相关子查询,它会对组件的每一行求值,因此不完全基于集合,这可以解释为什么这需要很长时间。非常感谢您的建议!!它提供了巨大的帮助!!这正是我想要的!!!:-)再次非常感谢!!!!!!!@mithilatw:不客气。请注意,此查询可能有两个问题(供将来参考):(1)这假设扫描的日期总是唯一的。如果两个扫描仪同时扫描(最高可达纳秒部分),则
选择组件id,扫描仪id
将返回2个值。(2)join
Temp2.scanner\u id=SL.scanner\u id
中的字段是基于字符的列,因此如果您有许多scanner\u id,则此查询可能会开始变慢。