4 postgresql constraint postgresql-9.2 check-constraints
我有以下错误:
ERROR: check constraint "cc_at_least_one_mapping_needed" is violated by some row
Run Code Online (Sandbox Code Playgroud)
询问:
ALTER TABLE integrations.tax_aggregates
DROP COLUMN IF EXISTS myob_id,
ADD COLUMN myob_id integrations.FOREIGN_IDENTIFIER;
COMMENT ON COLUMN integrations.tax_aggregates.myob_id IS 'Foreign key for MYOB';
ALTER TABLE integrations.tax_aggregates DROP CONSTRAINT IF EXISTS cc_at_least_one_mapping_needed,
ADD CONSTRAINT cc_at_least_one_mapping_needed CHECK ((("qb_id" IS NOT NULL) :: INTEGER +
("xero_id" IS NOT NULL) :: INTEGER +
("freshbooks_id" IS NOT NULL) :: INTEGER +
("myob_id" IS NOT NULL) :: INTEGER +
("ppy_id" IS NOT NULL) :: INTEGER) > 0);
DROP INDEX IF EXISTS integrations.ix_tax_aggregates_myob_ids_ids;
CREATE INDEX ix_tax_aggregates_myob_ids_ids ON integrations.tax_aggregates USING BTREE (myob_id)
WHERE myob_id IS NOT NULL;
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?我该如何解决问题?
更新:
询问:
ALTER TABLE integrations.accounts
DROP COLUMN IF EXISTS myob_settings,
ADD COLUMN myob_settings JSON;
ALTER TABLE integrations.accounts DROP CONSTRAINT IF EXISTS cc_at_least_one_setting_needed,
ADD CONSTRAINT cc_at_least_one_setting_needed CHECK (("qb_settings" IS NOT NULL) or
("xero_settings" IS NOT NULL) or
("freshbooks_settings" IS NOT NULL) or
("myob_settings" IS NOT NULL) or
("ppy_settings" IS NOT NULL));
Run Code Online (Sandbox Code Playgroud)
选择结果:
SELECT * FROM integrations.accounts WHERE qb_settings IS NOT NULL AND xero_settings IS NOT NULL and freshbooks_settings IS NOT NULL AND myob_settings IS NOT NULL AND ppy_settings IS NOT NULL
Run Code Online (Sandbox Code Playgroud)
它返回 0 行
SELECT * FROM integrations.accounts WHERE qb_settings IS NULL OR xero_settings IS NULL OR freshbooks_settings IS NULL OR myob_settings IS NULL OR ppy_settings IS NULL;
Run Code Online (Sandbox Code Playgroud)
返回(59 行):
"account_id"|"global_settings"|"qb_settings"|"xero_settings"|"freshbooks_settings"|"myob_settings"|"ppy_settings"
"30374"|""|"{""id"":""1412494720"",""active"":true,""settings"":{""secret"":""iisCCNSiH4jmRArWUPi0rxa9LntQdAA3kc7lbLtf"",""token"":""qyprdigrVpUijVKDxJ72iBZrnh4tvlwMA1QuVxxyPSgLIz4j"",""expires"":""2016-01-31 04:34:37""},""plan"":""QuickBooks Online Essentials""}"|""|""|""|""
ERROR: check constraint "cc_at_least_one_setting_needed" is violated by some row
Run Code Online (Sandbox Code Playgroud)
您有违反 CHECK CONSTRAINT 的 NULL。
要验证这确实是问题所在,请运行此 SQL。
SELECT * FROM integrations.accounts WHERE qb_settings IS NOT NULL OR
xero_settings IS NOT NULL OR... (fill in the fields that correspond to
those in the CONSTRAINT).
Run Code Online (Sandbox Code Playgroud)
这将为您提供所有包含违反约束的 NULL 值的字段的记录。
从您的 SQL 中,您有 59 条这样的记录 - 这就是您收到错误的原因。
您需要做的就是运行类似于以下内容的 SQL:
UPDATE My_Table SET My_Field = 0 WHERE My_Field IS NULL.
Run Code Online (Sandbox Code Playgroud)
显然,确保您设置的值符合您系统的业务逻辑和其他系统要求取决于您。
您可以否定您的约束以找出不满足它的行:
SELECT *
FROM integrations.accounts
WHERE NOT ((("qb_settings" IS NOT NULL) or
("xero_settings" IS NOT NULL) or
("freshbooks_settings" IS NOT NULL) or
("myob_settings" IS NOT NULL) or
("ppy_settings" IS NOT NULL)))
Run Code Online (Sandbox Code Playgroud)
这可以简化为:
WHERE
NOT NOT((("qb_settings" IS NULL) and
("xero_settings" IS NULL) and
("freshbooks_settings" IS NULL) and
("myob_settings" IS NULL) and
("ppy_settings" IS NULL)))
Run Code Online (Sandbox Code Playgroud)
并进一步作为:
WHERE
"qb_settings" IS NULL and
"xero_settings" IS NULL and
"freshbooks_settings" IS NULL and
"myob_settings" IS NULL and
"ppy_settings" IS NULL
Run Code Online (Sandbox Code Playgroud)
请注意,约束的规则是它们不能评估为False,Null满足约束,因此如果有可能评估为Null(不是在这种情况下),则必须考虑这一点。
从您的评论来看,您有兴趣按原样保留历史行,并且只验证新行。我能想到的两种选择:
向表中添加一个时间维度(比如在创建行时CREATE_TIME)并将约束更改为类似的内容:
ALTER TABLE integrations.accounts
ADD CONSTRAINT cc_at_least_one_setting_needed
CHECK ( (CREATE_TIME <= t_0) or
((qb_settings IS NOT NULL) or
(xero_settings IS NOT NULL) or
(freshbooks_settings IS NOT NULL) or
(myob_settings IS NOT NULL) or
(ppy_settings IS NOT NULL)) );
Run Code Online (Sandbox Code Playgroud)其中 t_0 是应验证行的时间。换句话说,它的含义是:(CREATE_TIME > t_0) => <your contraint>
创建触发器而不是检查约束。发生某些事情时会触发触发器,因此它们不关心已存在的行。就像是:
CREATE FUNCTION validate_row()
RETURNS trigger AS $validate_row$
BEGIN
-- Check that data is valid
IF NEW.qb_id IS NULL AND xero_id IS NULL AND ... THEN
RAISE EXCEPTION 'empname cannot be null';
END IF;
END;
$validate_row$ LANGUAGE plpgsql;
CREATE TRIGGER validate_row
BEFORE INSERT OR UPDATE ON integrations.accounts
FOR EACH ROW EXECUTE PROCEDURE validate_row();
Run Code Online (Sandbox Code Playgroud)这两个想法都未经测试。
| 归档时间: |
|
| 查看次数: |
11485 次 |
| 最近记录: |