Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
帮助处理复杂的SQL UPDATE语句_Sql_Postgresql - Fatal编程技术网

帮助处理复杂的SQL UPDATE语句

帮助处理复杂的SQL UPDATE语句,sql,postgresql,Sql,Postgresql,我有一个数据库表,需要在其上运行UPDATE语句。此表大约有250000条记录,因此优化性能非常重要 下面是相关的数据库模式和一些示例数据 audit_logs -- id -- ticket_id -- ip_address -- created_at -- -- 10 -- 100 -- 100.101.102.103 -- 2014-08-22 11:17:28.325844 -- -- 11 -- 100 -- 100.1

我有一个数据库表,需要在其上运行UPDATE语句。此表大约有250000条记录,因此优化性能非常重要

下面是相关的数据库模式和一些示例数据

audit_logs -- id -- ticket_id -- ip_address -- created_at -- -- 10 -- 100 -- 100.101.102.103 -- 2014-08-22 11:17:28.325844 -- -- 11 -- 100 -- 100.101.102.103 -- 2014-08-23 12:18:28.325844 -- -- 12 -- 101 -- 200.1.2.3 -- 2014-08-24 13:19:28.325844 -- -- 13 -- 101 -- 201.2.3.4 -- 2014-08-25 14:20:28.325844 -- -- 14 - 101 -- 202.3.4.5 -- 2014-08-26 15:21:28.325844 -- -- 15 - 102 -- 102.12.34.56 -- 2014-08-27 16:22:28.325844 -- 这是我需要做的。对于任何具有超过1个IP地址的记录的ticket_id,我需要为每个IP地址(第一个除外)将ticket_id设置为NULL。下面是上述数据的示例结果

audit_logs -- id -- ticket_id -- ip_address -- created_at -- -- 10 -- 100 -- 100.101.102.103 -- 2014-08-22 11:17:28.325844 -- -- 11 -- 100 -- 100.101.102.103 -- 2014-08-23 12:18:28.325844 -- -- 12 -- 101 -- 200.1.2.3 -- 2014-08-24 13:19:28.325844 -- -- 13 -- NULL -- 201.2.3.4 -- 2014-08-25 14:20:28.325844 -- -- 14 - NULL -- 202.3.4.5 -- 2014-08-26 15:21:28.325844 -- -- 15 - 102 -- 102.12.34.56 -- 2014-08-27 16:22:28.325844 -- 因此,同一票据可以有多条记录。但是,如果一个票证关联的IP地址超过1个,则每个IP地址不是第一个记录的记录都需要清空


我使用的实际RDBMS是Postgres。最简单的方法是什么?谢谢大家。

开始尝试类似的方法,以后再优化

UPDATE audit_logs O
SET ticket_id = NULL
WHERE (
    SELECT count(distinct ip_address)
    FROM audit_logs I WHERE I.ticket_id = O.ticket_id
) > 1 AND id <> (
    SELECT DISTINCT ON (id) id
    FROM audit_logs I WHERE I.ticket_id = O.ticket_id
) AND ip_address <> (
    SELECT DISTINCT ON (ip_address) ip_address
    FROM audit_logs I WHERE I.ticket_id = O.ticket_id
)

另外,我的PostgreSQL已经生锈了,所以语法可能有点不正确。。。对不起,我的家用计算机上也没有安装PostgreSQL进行检查。

不幸的是,Postgres还不支持countdistinct。。作为一个窗口函数,它比必要的要复杂一些:

update audit_logs
  set ticket_id = null
from (
  select a.id, 
         a.ticket_id,
         row_number() over (partition by a.ticket_id order by a.created_at) as rn
  from audit_logs a
  join  (
    select ticket_id
    from audit_logs
    group by ticket_id
    having count(distinct ip_address) > 1
  ) t on t.ticket_id = a.ticket_id
) x
where x.id = audit_logs.id
and x.rn > 1;
SQLFiddle:

最内层的select别名t get具有多个IP地址的所有票证id。然后将其与基表联接以计算行数。然后在更新中使用该结果来查找应更新的行


不确定性能,这在很大程度上取决于最里面的select将返回多少行。

如何确定哪一行是“第一行”;创建日期?可能是两件事之一。给定票证id的最小“创建时间”或最小“id”值。对两条记录进行排序应产生相同的结果。不,记录11的票证id不应为空,因为记录10和11的IP地址值相同。我只想在IP地址不同时将票证清空。是否可以使用具有多个重复IP地址的票证id?e、 g.票证id 101可能有一个ip地址为200.1.2.3的额外行;如果是这样,您希望仅保留第一行而不为空还是保留第一个ip_地址?即使跨多个记录,也应保留第一个ip_地址/票证id配对。但是,如果以后的记录中出现了另一个IP地址,并且该IP地址具有相同的票证id,则该票证id应设置为NULL。实际上,下面有一个答案,它按照预期工作。不仅工作正常,而且运行时间约为6秒!在25万张唱片中,约有14万张被点击。我运行了一个验证查询,一切顺利。非常感谢。