我試圖弄清楚如何在 CREATE TABLE 之外撰寫和添加一般約束,其中當 payDate 是 New Years 2010 (01-01-2010) 時,不同員工的收入必須超過 100,000 美元。該日期的一些收入資料為 NULL,但我只是想找到大于 10 萬美元的收入。
我正在使用的表:
Employees | Date | Income
John |12-01-2009| 50000
Jake |12-01-2009| 70000
Jill |12-21-2009| 85000.75
Jonn |12-27-2009| 120000.5
June |01-01-2010| 100000.25
Joey |01-01-2010| \N
Jack |01-01-2010| 120000
Jane |01-01-2010| 110000.75
Jean |01-01-2010| \N
Joon |01-01-2010| \N
我試過了:
ALTER TABLE Employees
ADD CONSTRAINT nyIncome
CHECK(payDate = DATE '2010-01-01' AND income > 100000 AND income IS NOT NULL);
這給了我:
"ERROR: check constraint nyIncome is violated by some row"
我將如何修復我的支票以使其滿足條件?
編輯:我的初始約束不起作用的原因是表中還有其他日期未在條件中指定。
Jonas 提供的解決方案:
ALTER TABLE Employees ADD CONSTRAINT nyIncome CHECK (payDate != '2010-01-01' OR (payDate = '2010-01-01' AND (income > 100000 OR income IS NULL)));
此解決方案將遍歷所有 payDates 并創建一個特定條件,其中“2010-01-01”日期的收入必須高于 100000,例如,一個日期為“2010-01-01”的元組和收入為80,000 將不滿足此限制,因此無法插入,或者無法將“2010-01-01”日期的收入更新為收入低于 100000。
uj5u.com熱心網友回復:
如果您的表中有一個或多個已存在的記錄未通過檢查約束,則會顯示您看到的確切錯誤訊息。要查找此類記錄,您可以使用以下查詢:
SELECT *
FROM Employees
WHERE payDate <> '2010-01-01' OR income > 100000 OR income IS NOT NULL;
實際上,您的檢查約束非常具體,在我看來,大多數資料都無法匹配它。也許您打算對此檢查約束的否定:
ALTER TABLE Employees
ADD CONSTRAINT nyIncome
CHECK (payDate <> '2010-01-01' OR income > 100000 OR income IS NOT NULL);
uj5u.com熱心網友回復:
當某些條目不滿足約束條件時,您無法在現有表上創建約束。如果您確實需要檢查所有這些條件,則必須在創建約束之前更新已經存在的條目以確保所有行都滿足條件。或者如果這不是故意的,您需要創建一個插入前觸發器而不是一個約束來檢查是否允許新條目。如果您創建這樣的觸發器,您還應該檢查在插入之前是否足夠或是否應該在更新之前完成。在您的情況下,您的約束條件似乎不正確。可能正確的語法(根據您的描述)將是:
ALTER TABLE Employees
ADD CONSTRAINT nyIncome
CHECK (payDate = '2010-01-01' AND (income > 100000 OR income IS NULL));
如果您不確定約束的正確條件,請先執行一個選擇,其中包含您要通過約束檢查的 where 子句的確切條件,并查看結果是否是整個表。或者還原 where 子句并檢查結果是否為空。
更新,因為您編輯了您的問題:您無法創建這樣的約束,因為您的表中還有其他日期的條目。您可能需要一個觸發器來禁止插入/更新收入 <= 100000 且日期為“2010-01-01”的條目。或者,如果這些限制僅應用于查詢,則只需在查詢中創建精確的 where 子句而不是觸發器。
uj5u.com熱心網友回復:
當 payDate 是 New Years 2010 (01-01-2010) 時,不同員工的收入必須超過 $100,000。該日期的某些收入資料為 NULL,
其他人已經指出,您不能對 (paydate = 2010-01-01 then income is not null) 使用檢查約束,因為某些行違反了條件。
因此,以下答案適用于設定約束:如果 paydate = 2010-01-01 那么收入 = null 或收入 > 100000。
通過檢查約束。意思是檢查當前行和傳入行。如果不符合標準,則將呼叫錯誤。
ALTER TABLE emp
ADD CONSTRAINT nyIncome CHECK (
(payDate = DATE '2010-01-01' AND income > 100000)
OR (payDate = DATE '2010-01-01' AND income IS NULL)
OR (payDate <> DATE '2010-01-01'));
drop trigger trg_special_date on emp;
通過觸發器。顯然觸發器不會驗證現有行。
CREATE OR REPLACE FUNCTION trg_special_date ()
RETURNS TRIGGER
AS $$
BEGIN
IF NEW.paydate = '2010-01-01' THEN
IF NEW.income IS NULL THEN
RETURN new;
elsif NEW.income > 100000 THEN
RETURN new;
ELSE
RETURN NULL;
END IF;
ELSE
RETURN new;
END IF;
END;
$$
LANGUAGE plpgsql;
CREATE TRIGGER trg_special_date
BEFORE INSERT OR UPDATE ON emp FOR EACH ROW
EXECUTE PROCEDURE trg_special_date ();
注意:此觸發器將簡單地忽略不符合條件的行,您可以自定義它,因此如果傳入的行不符合條件則呼叫錯誤。
另一種方法是行級安全性,有點難。另一種方法是使用 security_barrier 或 security_invoker 或 check_option 查看。(將來會這樣做)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/476576.html
標籤:sql PostgreSQL 检查约束
