【问题标题】:SQL Query to update the value of column of one table based on condition on two different tablesSQL查询根据两个不同表的条件更新一个表的列的值
【发布时间】:2015-11-16 13:32:09
【问题描述】:

我有三张桌子:

INDICATOR
---------------------   
 ID  | INDICATOR_NEW
---------------------
 001 | 1
 002 | 1
 003 | 1


DETAILS
------------------------
 ID  | ADD  | POSTDATE
------------------------
 001 | ADD1 | 02-AUG-15    
 001 | ADD2 | 09-AUG-15
 002 | ADD1 | 09-AUG-15    
 002 | ADD2 | 02-AUG-15


HISTORY
--------------------------------
 ID  | ADD  | STARTDATE | VALUE
--------------------------------
 001 | ADD1 | 02-AUG-15 | 100        
 001 | ADD2 | 09-AUG-15 | 10        
 002 | ADD1 | 09-AUG-15 | 20        
 002 | ADD2 | 02-AUG-15 | 25

我必须编写一个 SQL 代码,根据以下检查将 INDICATOR 表的 INDICATOR_NEW 值更新为 0:

  1. IDINDICATOR 表存在于 DETAILS 表中。
  2. 上述 id 的记录存在于HISTORY 表中,并且ID 保存HISTORY.MAX(STARTDATE) = DETAILS.POSTDATE - 7

我正在尝试使用以下查询获取结果:

 UPDATE INDICATOR
    SET INDICATOR_NEW = 0
  WHERE INDICATOR_NEW = 1
   AND EXISTS (SELECT 1
                 FROM DETAILS D1
                WHERE ID = D1.ID)
   AND EXISTS( SELECT 1 
                 from (SELECT MAX(STARTDATE) OVER(PARTITION BY ID) RN,ID
                         from HISTORY H1)T1,
                      DETAILS D1
                WHERE T1.RN = D1.DMDPOSTDATE - 7
                 AND T1.ID = D1.ID);

这是获得所需结果的正确方法还是应该使用GROUP BY 而不是PARTITION BY(考虑性能效率)?

【问题讨论】:

  • 如果是T-SQL(决定你使用mysql/orace/sqlserver)标签,你绝对可以将第一部分简化为UPDATE INDICATOR SET INDICATOR_NEW = 0 FROM INDICATOR i JOIN DETAILS D1 ON i.ID = D1.ID ...
  • 谢谢。那么它会提高代码的性能吗? ?你也可以建议第二部分吗??
  • 如果您使用 SqlFiddle 准备结构、示例数据和共享链接,帮助会容易得多。
  • 不要用多个数据库标记问题,除非你需要解决所有问题(如果是这样,应该在问题中指出),这只是令人困惑,因为不同的数据库使用不同的语法,所以例如,为 MSSQL 编写的答案不适用于 MySQL 等。只需包含您实际使用的数据库即可。
  • 我想回答我的 sql。谢谢。

标签: mysql sql sql-server oracle sql-update


【解决方案1】:
  • 您应该为indicator 使用别名,比如I
  • 首先exists,我猜你的意思是I.ID = D1.ID
  • 第二个exists,我没看到你用outer table,所以结果总是一样的。也要小心,因为我认为查询总是会返回一个值。
  • 对于这种情况,group by 会给你同样的结果。

.

UPDATE  INDICATOR I -- include alias
SET INDICATOR_NEW = 0
WHERE 
    INDICATOR_NEW = 1
AND EXISTS
    (SELECT 1
     FROM DETAILS D1
     WHERE ID = D1.ID) -- use I.ID if that is the case
AND EXISTS
    (SELECT 1 
     FROM (SELECT H1.ID, MAX(H1.STARTDATE) RN
           FROM HISTORY H1
           GROUP BY H1.ID
          )T1 , DETAILS D1
     WHERE T1.RN = D1.DMDPOSTDATE - 7
     AND   T1.ID = D1.ID  -- here you aren't using outer table so always same result
  )

【讨论】:

  • 所以性能明智的 GROUP BY 在这里使用而不是 PARTITION BY 更好?
  • 我不确定,您必须执行分析才能进行比较。我的猜测可能是一样的。但是group by 对我来说很容易阅读。
  • 嗨胡安..感谢您的帮助。但是你能不能修改上面的代码,以便 INDICATOR 表中的值只有在 DETAILS 和 HISTORY 表中存在并且 MAX(HISTORY.STARTDATE) = DETAILS.DMDPOSTDATE - 7 时才会更新
  • 非常感谢胡安您的帮助。 :)
  • 我不介意帮忙。但提出此类问题的最佳方式是显示您的架构,提供一些输入数据和您想要的结果。你有前两个仍然需要欲望输出。你可以修改你的问题,让我知道。如果您提供SQLfiddle 也会有所帮助,这样我就可以提供可行的解决方案
猜你喜欢
  • 2013-01-21
  • 1970-01-01
  • 2020-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多