根据选定列中的相同值向行添加数字

Posted

技术标签:

【中文标题】根据选定列中的相同值向行添加数字【英文标题】:Add number to rows based on identical values in selected columns 【发布时间】:2012-03-08 03:57:21 【问题描述】:

我有一个 PostgreSQL 数据库,其中包含由几个司法管辖区编写的交通罚单。

一些司法管辖区没有说明是否在一个交通站点中写入了多张罚单。但是,这可以通过分析其他领域来推断。考虑这些数据:

ticket_id  timestamp            drivers_license
----------------------------------------------
1          2008-08-07 01:51:00  11111111
2          2008-08-07 01:51:00  11111111
3          2008-08-07 02:02:00  22222222
4          2008-08-07 02:25:00  33333333
5          2008-08-07 04:23:00  44444444
6          2008-08-07 04:23:00  55555555
7          2008-08-07 04:23:00  44444444

我可以推断:

票 1 和 2 写在一个交通站,因为它们共享驾驶执照号码和时间戳。 5 和 7 相同,但请注意票 6 在它们之间的位置。也许另一名官员同时在其他地方写了一张罚单,或者数据输入操作员输入了乱序的东西。

我想为每个交通站点添加另一个具有唯一 ID 的列。它不会是表的主键,因为它会有重复的值。例如:

ticket_id  timestamp            drivers_license  stop_id
--------------------------------------------------------
1          2008-08-07 01:51:00  11111111         1
2          2008-08-07 01:51:00  11111111         1
3          2008-08-07 02:02:00  22222222         2
4          2008-08-07 02:25:00  33333333         3
5          2008-08-07 04:23:00  44444444         4
6          2008-08-07 04:23:00  55555555         5
7          2008-08-07 04:23:00  44444444         4

我可以想到用 C# 执行此操作的计算密集型、贪心算法的方法,但是是否有有效的 SQL 查询可以工作?

【问题讨论】:

我看不出简单地添加另一列与已经拥有驾驶执照的外键有什么不同... 时间戳不同。 是的。可以在不同场合引用单个驾驶者(单个 DL)。 【参考方案1】:

如果您使用window function rank(),这将变得非常简单:

SELECT *
      ,rank() OVER (ORDER BY ts, drivers_license)
FROM   tbl
ORDER  BY ticket_id

准确地返回您要求的内容。

我将您的列 timestamp 重命名为 ts,因为 timestamp 在 PostgreSQL 中是一个类型名称,在每个 SQL 标准中都是一个 reserved word。

【讨论】:

【参考方案2】:

高效的 SQL 查询 FTW!

我不在可以测试它的计算机上,因此可能存在一些语法问题;我会在早上修复,但它是这样的:

WITH uniquez as (SELECT timestamp, drivers_license, 
rank() over (ORDER BY timestamp, drivers_license) as counterz 
FROM ticketTable)

UPDATE ticketTable TT
SET stop_id = uniquez.counterz
WHERE uniquez.timestamp = TT.timestamp
AND uniquez.drivers_license = TT.drivers_license

基本上,您可以选择按时间戳和 drivers_license 分组(分区),并有一个与之配套的行计数器。当您进行更新时,您使用这个先前选择表的行计数器作为您的“stop_id”并更新与时间戳和驾驶执照匹配的列。

【讨论】:

无论 postgreSQL 是否允许,在没有 ORDER BY 子句的情况下使用 ROW_NUMBER() 是一个非常糟糕的主意。无论如何,我认为您在这里所拥有的根本不起作用。如果按时间戳、drivers_license 分区,则每次时间戳、drivers_license 更改时,行编号都会再次从 1 开始。如果您将 partition by 更改为 ORDER BY,您会更接近,但我认为您需要 DENSE_RANK(),而不是 row_number()。 @SteveKass 绝对同意。深夜编程会对事情产生这种影响。我会编辑。 -1 您只是将我的正确版本复制到不正确的版本上,而没有注明。这不是这里推荐的方式 - 礼貌地说。 我在基于此构建的查询中遇到了一个奇怪的错误。我在***.com/questions/9643859/… 开了一个单独的问题。 原来您在 UPDATE 语句中缺少 FROM 子句。在 SET 行之后,您需要一个 FROM uniquez【参考方案3】:

您最好的选择可能是创建一个带有 DISTINCT 时间戳和驾驶执照编号的新表(例如“stops”),分配行号,然后从该新表更新票证表。

【讨论】:

【参考方案4】:
SELECT ticket_id,timestamp,drivers_license,substr(drivers_license,1,1) as stop_id
FROM traffic_data;

希望这对你有用... :)

【讨论】:

一个人可能会在不同的站点收到不同的票,所以很遗憾,这行不通。

以上是关于根据选定列中的相同值向行添加数字的主要内容,如果未能解决你的问题,请参考以下文章

根据前一行的内容向行添加新值

根据列中的“是”或“否”仅绘制选定的行

基于列值向sql中的列添加行值

如何根据下拉列表中的选定数字生成表单输入字段(选择)

如何将空行添加到网格并填充列,然后在EXTJS中提交

使用选定时间段从数据库中的一列或两列中计算大量内容的有效方法