gpt4 book ai didi

ruby-on-rails - 当我为列设置默认函数时,为什么 Postgres 会双引号第一个函数标识符?

转载 作者:行者123 更新时间:2023-11-29 13:47:00 25 4
gpt4 key购买 nike

我在 Rails 项目中有一个带有默认表达式的旧表。此表达式选择一个随机的四位数并将其转换为字符串。在我的测试中,我一直在 psql 中输入这个确切的语句来设置默认表达式:

alter table owners alter column signing_code set default 
substring(to_char(((random() * ((10000 - 1))::double precision) +
(1)::double precision), '0000'::text), '....$'::text);

然后当我执行 \d owners 时,Postgres 决定这是我实际的默认表达式:

default "substring"(to_char(((random() * ((10000 - 1))::double 
precision) + (1)::double precision), '0000'::text), '....$'::text)

请注意第一个函数标识符 substring 周围的双引号。这会导致 Rails 模式转储/加载出现两个问题:

  1. 将架构转储到 db/schema.rb 时,会生成无效的 Ruby,因为双引号未转义
  2. 即使您手动正确地转义引号,当将模式加载回数据库时,Rails 会错误地将整个表达式设置为默认字符串值,而不是表达式(即用单引号将表达式括起来)

在我的例子中,有没有办法让 Postgres 在嵌套函数调用中不对第一个函数进行双引号?这将是一个很好的解决方法,否则我将提交 Rails 项目的错误。

最佳答案

为什么 substring 函数被双引号括起来并不重要,这两个表达式在功能上是等价的。 PostgreSQL 将解析默认表达式,然后保存解析后的版本,在此过程中,substring 标识符被双引号括起来。如果像这样添加 CHECK 约束,您会看到类似的事情发生:

check (c in (1, 2, 3))

在具有该约束的表上执行 \d 将得到:

CHECK (c = ANY (ARRAY[1, 2, 3]))

PostgreSQL 将 in 表达式转换为等效的 = ANY 表达式,因为这是它希望在内部使用的内容。这两个表达式在功能上是等价的。

真正的问题是 ActiveRecord 不知道如何处理比单个文字值更复杂的默认表达式。 AR 对默认值做出了一个无效的假设,然后盲目地把事情弄得一团糟。

当您处理任何超出最简单的 DDL SQL 的事情时,您最好的选择是使用 db/structure.sql 而不是 db/schema.rbstructure.sql 使用数据库的本地转储/恢复工具,因此它将理解并保留数据库所知道的一切。

切换到 structure.sql 非常简单:

  1. 更新 config/application.rb 以使用正确的格式:

    config.active_record.schema_format = :sql
  2. 使用 db:structure:dump rake 任务转储您的 structure.sql

  3. 从源代码树和版本控制中删除 db/schema.rb

  4. db/structure.sql 添加到版本控制。

  5. 重新训练您的手指使用不同的 rake 任务来转储和恢复架构:

    • db:structure:dump 而不是 db:schema:dump
    • db:structure:load 而不是 db:schema:load

我总是从 structure.sql 开始,因为 schema.rb 对于我想如何使用我的数据库来说太有限了。

关于ruby-on-rails - 当我为列设置默认函数时,为什么 Postgres 会双引号第一个函数标识符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46795959/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com