Android 能否根据SQLite中前两列的计算设置列的默认值?

Android 能否根据SQLite中前两列的计算设置列的默认值?,android,sql,database,sqlite,Android,Sql,Database,Sqlite,我在SQLite中有一个表,我想根据前两列的输入值设置第三列的值 SQLite是否支持列的默认值中的表达式 create table contract( id primary key autoincrement, insurance_pct integer not null default 0, historical_yield integer not null default 0, guaranteed_yield intege

我在SQLite中有一个表,我想根据前两列的输入值设置第三列的值

SQLite是否支持列的默认值中的表达式

create table contract(
   id                primary key autoincrement,
   insurance_pct     integer not null default 0,
   historical_yield  integer not null default 0,
   guaranteed_yield  integer not null default (insurance_pct/100 * historical_yield)
)
当我运行上述语句时,我看到以下错误

查询执行失败

原因:

SQL错误[1]:[SQLITE_Error]SQL错误或缺少数据库(列[Guaranted_YIELD]的默认值不是常量)


SQLite不支持这一点

各国:

显式DEFAULT子句可以指定默认值为NULL、字符串常量、blob常量、有符号数字或括号中包含的任何常量表达式

此外,本文件定义了常量表达式的概念:

对于DEFAULT子句,如果表达式不包含子查询、列或表引用、绑定参数或用双引号而不是单引号括起来的字符串文字,则该表达式被视为常量

这就排除了对其他列的引用

用例中的其他可能方法:

  • 动态计算DML查询中的值(更新和插入)
  • 使用触发器提供DML操作的动态默认值
由于错误消息“列[Guaranted_YOUD]的默认值不是常量”明确指出,您不能在默认表达式中使用变量

实现所需功能的一种方法是创建一个after-insert触发器,当列作为null插入时更新该列。但是,这要求列不声明为not null,否则
INSERT
将失败。所以你也必须在更新前触发器中检查

CREATE TABLE contract
             (id integer PRIMARY KEY
                         AUTOINCREMENT,
              insurance_pct integer
                            NOT NULL
                            DEFAULT 0,
              historical_yield integer
                               NOT NULL
                               DEFAULT 0,
              guaranteed_yield integer
                               NULL
                               DEFAULT NULL);

CREATE TRIGGER contract_ai
               AFTER INSERT
                     ON contract
               FOR EACH ROW
               WHEN (new.guaranteed_yield IS NULL)
BEGIN
  UPDATE contract
         SET guaranteed_yield = insurance_pct / 100 * historical_yield
         WHERE id = new.id;
END;

CREATE TRIGGER contract_bu
               BEFORE UPDATE
                      ON contract
               FOR EACH ROW
               WHEN (new.guaranteed_yield IS NULL)
BEGIN
  SELECT raise(FAIL, 'NOT NULL constraint failed: contract.guaranteed_yield');
END;
我注意到另一件事:
保证收益率
是一个整数,但您的默认表达式很可能生成非整数值。由于所需的舍入,您可能会丢失某些内容。我不确定这是否是故意的


增编:


查看对您的问题的评论,我不确定您是否只想要一个默认值,即
保证收益率
的值应该具有表达式的值,如果在
插入
中没有明确给出其他值,但它可能具有其他值(非空)来自
插入
或后续
更新
的值,或者如果您打算将其作为计算列,则始终具有表达式给出的值。在后一种情况下:我支持其他评论者。对于不一致性,这是一个潜在的危险因素。最好在查询中使用表达式或创建视图。

sqlite手册中的“创建表”文档不清楚吗?它确实支持默认值的表达式,但我很确定无法引用插入行的其他列。在这种情况下,因为它非常简单,所以在需要时(可能在视图中)只需动态计算值,而不是使用列。是的,我同意这里的计算非常简单和直接,但这里的要点是代码越少,错误就越少。为什么要在你的代码中写一些东西,而供应商的软件可以在不引入任何bug的情况下动态地为你做呢?这是一个与SQLite特性相关的有效问题,不知道为什么会被否决。虽然我很欣赏随答案提供的反馈、评论和逻辑,但这只是开发人员希望将业务逻辑放在何处的品味问题。@user2325154::这当然是一个有效的问题,但我不同意创建一个列来存储“业务逻辑”的“优势”。当业务逻辑在某个时刻发生变化时会发生什么?留下的列中充满了无用的、潜在危险的数据——这些数据无法更改,因为它们“硬连接”到数据库。您已经准备用一个简单的SQL“SELECT”语句查询数据库了。将计算添加到语句中不应引入任何您的建议无法引入的错误。@user2325154:另请参阅我的附录。