如何在更新时转换 varchar?
How to cast varchar on update?
当我更新 t1 时,"VALUE"
字段应该递增
但此字段设置为 VARCHAR
,我会将其转换为 INTEGER
:
UPDATE t1 SET "VALUE"="VALUE"+1
WHERE NOT EXISTS (
SELECT "VALUE" FROM t1 WHERE CAST(t1."VALUE" as INTEGER) = t2."VALUE");
您需要将 "VALUE"
转换为整数才能增加它,因此:
UPDATE t1 SET "VALUE" = CAST("VALUE" as INTEGER) + 1
Firebird 会在分配时自动将 INTEGER
转换回 VARCHAR
。
参见 this dbfiddle。
也就是说,处理此问题的正确方法是更改架构并为此列使用 INTEGER
类型。
您已经键入 WHERE CAST(t1."VALUE" as INTEGER)
- 这正是您必须要做的。
UPDATE t1 SET VALUE = CAST(CAST(VALUE as INTEGER) + 1 AS VarChar(10))
就像马克上面说的。
让我烦恼的是你的 WHERE
条款。
WHERE NOT EXISTS
在 interbase/firebird 上的数据量超过微不足道时可能会非常慢。早在 1990 年代的 Interbase 5.6 天,我就使用这样的结构从下到上计算 MLM 树。我认为它是有利的,因为不会涉及未知深度递归,并且因为如果树被分裂并且不能从一个根访问所有 - 对于 bototm-up ascend 它没有问题。
原来,仅仅 60000 行就花了大约 2 个小时。过去常常用铅笔和纸计算数周的老板们没有发现任何问题。但我知道有些事情很糟糕(它是 - 忽略索引并使用嵌套自然扫描,O(n ^ 2)缩放)。
请三思使用 WHERE NOT EXIST
,在某些模式和数据上它是好的甚至是最好的方法,在其他模式和数据上可能会迅速升级为几乎无法使用的程序。 DailyWTF 定期撰写有关在开发期间在小型数据集上完美运行但在部署到生产几个月后停止运行的程序。诚然,我的第一个 SQL 程序就是其中之一...
此外,您的查询似乎完全错误。什么是 t2.VALUE
?当您使用相等表达式时,您必须给出一个单独的标量值。但是 t2.Value 只是一列,它可以有零行或千行。
这个 WHERE
子句似乎被破坏了,我相信你编造了它并且实际上从未在服务器上 运行。你真正的查询是什么?现在您的查询看起来像
IF there is somewhere a row in T1, where value is same as (T2-VALUE constant???)
THEN do nothing
ELSE update every row in T1 by incrementing VALUE column
或者您的意图不同?
IF there are any rows in T1 and T2 with the same value in their VALUE columns
THEN do nothing
ELSE update every row in T1 by incrementing VALUE column
在这两种情况下,这是一次性检查,必须在 UPDATE 序列之前完成一次,而不是在 T1 行上一次又一次地进行 运行。这正是制作非缩放应用程序的秘诀。
将计算不变量移出循环。
作为一般性建议,要避免多个 WHERE NOT EXISTS
您至少有两个足够通用的工具。
- 使用控制反转。使用
for select ... do ...
循环制作一个 PSQL 块( 存储过程 或匿名 EXECUTE BLOCK
)。
用IS NULL
检查通常的LEFT JOIN
,作为WHERE NOT EXIST
的替代。
在循环内只对那些必须更新的行调用 UPDATE。
- 使用
MERGE
命令,而不是 PSQL 循环。
但很可能,您的查询几乎与您手头的实际任务无关。所以我们也不能给出合理的建议。
当我更新 t1 时,"VALUE"
字段应该递增
但此字段设置为 VARCHAR
,我会将其转换为 INTEGER
:
UPDATE t1 SET "VALUE"="VALUE"+1
WHERE NOT EXISTS (
SELECT "VALUE" FROM t1 WHERE CAST(t1."VALUE" as INTEGER) = t2."VALUE");
您需要将 "VALUE"
转换为整数才能增加它,因此:
UPDATE t1 SET "VALUE" = CAST("VALUE" as INTEGER) + 1
Firebird 会在分配时自动将 INTEGER
转换回 VARCHAR
。
参见 this dbfiddle。
也就是说,处理此问题的正确方法是更改架构并为此列使用 INTEGER
类型。
您已经键入 WHERE CAST(t1."VALUE" as INTEGER)
- 这正是您必须要做的。
UPDATE t1 SET VALUE = CAST(CAST(VALUE as INTEGER) + 1 AS VarChar(10))
就像马克上面说的。
让我烦恼的是你的 WHERE
条款。
WHERE NOT EXISTS
在 interbase/firebird 上的数据量超过微不足道时可能会非常慢。早在 1990 年代的 Interbase 5.6 天,我就使用这样的结构从下到上计算 MLM 树。我认为它是有利的,因为不会涉及未知深度递归,并且因为如果树被分裂并且不能从一个根访问所有 - 对于 bototm-up ascend 它没有问题。
原来,仅仅 60000 行就花了大约 2 个小时。过去常常用铅笔和纸计算数周的老板们没有发现任何问题。但我知道有些事情很糟糕(它是 - 忽略索引并使用嵌套自然扫描,O(n ^ 2)缩放)。
请三思使用 WHERE NOT EXIST
,在某些模式和数据上它是好的甚至是最好的方法,在其他模式和数据上可能会迅速升级为几乎无法使用的程序。 DailyWTF 定期撰写有关在开发期间在小型数据集上完美运行但在部署到生产几个月后停止运行的程序。诚然,我的第一个 SQL 程序就是其中之一...
此外,您的查询似乎完全错误。什么是 t2.VALUE
?当您使用相等表达式时,您必须给出一个单独的标量值。但是 t2.Value 只是一列,它可以有零行或千行。
这个 WHERE
子句似乎被破坏了,我相信你编造了它并且实际上从未在服务器上 运行。你真正的查询是什么?现在您的查询看起来像
IF there is somewhere a row in T1, where value is same as (T2-VALUE constant???)
THEN do nothing
ELSE update every row in T1 by incrementing VALUE column
或者您的意图不同?
IF there are any rows in T1 and T2 with the same value in their VALUE columns
THEN do nothing
ELSE update every row in T1 by incrementing VALUE column
在这两种情况下,这是一次性检查,必须在 UPDATE 序列之前完成一次,而不是在 T1 行上一次又一次地进行 运行。这正是制作非缩放应用程序的秘诀。
将计算不变量移出循环。
作为一般性建议,要避免多个 WHERE NOT EXISTS
您至少有两个足够通用的工具。
- 使用控制反转。使用
for select ... do ...
循环制作一个 PSQL 块( 存储过程 或匿名EXECUTE BLOCK
)。
用IS NULL
检查通常的LEFT JOIN
,作为WHERE NOT EXIST
的替代。
在循环内只对那些必须更新的行调用 UPDATE。
- 使用
MERGE
命令,而不是 PSQL 循环。
但很可能,您的查询几乎与您手头的实际任务无关。所以我们也不能给出合理的建议。