英文:
Querying foreign keys different results
问题
I am writing some code that will disable and enable foreign keys on a table. It appears to run fine. When I check the status of the Foreign key immediately executing the code the status appears to be unchanged with one query and changed with a different query.
我正在编写一些代码,用于在表上禁用和启用外键。代码似乎运行正常。当我立即执行代码并检查外键的状态时,一个查询显示状态未更改,而另一个查询显示状态已更改。
I can't seem to figure out what the problem is and was hoping someone can help me out and explain this anomaly and or suggest a fix to my code.
我似乎无法弄清楚问题出在哪里,希望有人可以帮助我解释这个异常或建议修复我的代码。
Below is my test CASE along with sample data to show what I have done.
以下是我的测试用例以及示例数据,以展示我所做的事情。
英文:
I am writing some code that will disable and enable foreign keys on a table. It appears to run fine. When I check the status of the Foreign key immediately executing the code the status appears to be unchanged with one query and changed with a different query.
I can't seem to figure out what the problem is and was hoping someone can help me out and explain this anomaly and or suggest a fix to my code.
Below is my test CASE along with sample data to show what I have done.
CREATE TABLE customers
(CUSTOMER_ID, FIRST_NAME, LAST_NAME) AS
SELECT 1, 'Faith', 'Mazzarone' FROM DUAL UNION ALL
SELECT 2, 'Lisa', 'Saladino' FROM DUAL UNION ALL
SELECT 3, 'Micheal', 'Palmice' FROM DUAL UNION ALL
SELECT 4, 'Joseph', 'Zaza' FROM DUAL UNION ALL
SELECT 5, 'Jerry', 'Torchiano' FROM DUAL;
ALTER TABLE customers
ADD CONSTRAINT customers_pk PRIMARY KEY (customer_id);
CREATE TABLE items
(PRODUCT_ID, PRODUCT_NAME, PRICE) AS
SELECT 100, 'Black Shoes', 79.99 FROM DUAL UNION ALL
SELECT 101, 'Brown Pants', 111.99 FROM DUAL UNION ALL
SELECT 102, 'White Shirt', 10.99 FROM DUAL;
ALTER TABLE items
ADD CONSTRAINT items_pk PRIMARY KEY (product_id);
create table purchases(
ORDER_ID NUMBER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
customer_id number,
PRODUCT_ID NUMBER,
QUANTITY NUMBER,
purchase_date timestamp
);
insert into purchases (customer_id, product_id, quantity, purchase_date)
SELECT 3, 102, 4,TIMESTAMP '2022-12-22 21:44:35' + NUMTODSINTERVAL ( LEVEL * 2, 'DAY') FROM dual
CONNECT BY LEVEL <= 15 UNION ALL
select 1, 101,3, date '2023-03-29' + level * interval '2' day from dual
connect by level <= 12
union all
select 2, 101,2, date '2023-01-15' + level * interval '8' hour from dual
connect by level <= 15
union all
select 2, 102,2,date '2023-04-13' + level * interval '1 1' day to hour from dual
connect by level <= 11
union all
select 3, 101,2, date '2023-02-01' + level * interval '1 05:03' day to minute from dual
connect by level <= 10
union all
select 3, 101,1, date '2023-04-22' + level * interval '23' hour from dual
connect by level <= 23
union all
select 3, 100,1, date '2022-03-01' + level * interval '1 00:23:05' day to second from dual
connect by level <= 15
union all
select 4, 102,1, date '2023-01-01' + level * interval '5' hour from dual
connect by level <= 60;
ALTER TABLE purchases
ADD CONSTRAINT order_pk PRIMARY KEY (order_id);
ALTER TABLE purchases ADD CONSTRAINT customers_fk FOREIGN KEY (customer_id) REFERENCES customers(customer_id);
ALTER TABLE purchases ADD CONSTRAINT items_fk FOREIGN KEY (PRODUCT_ID) REFERENCES items(product_id);
/* both queries fine here */
SELECT '"' || a.owner
|| '"."'
|| a.table_name
|| '"' AS full_table_name,
a.constraint_name,
b.status
FROM user_constraints a
JOIN user_constraints b
ON ( a.r_constraint_name = b.constraint_name
AND a.r_owner = b.owner )
WHERE a.constraint_type = 'R'
AND b.status = 'ENABLED'
ORDER BY 1
FULL_TABLE_NAME
CONSTRAINT_NAME STATUS
"XXX"."PURCHASES" ITEMS_FK ENABLED
"XXX"."PURCHASES" CUSTOMERS_FK ENABLED
select owner, table_name, r_constraint_name, status
from user_constraints
where constraint_type = 'R';
OWNER TABLE_NAME R_CONSTRAINT_NAME STATUS
XXX PURCHASES CUSTOMERS_PK ENABLED
XXX PURCHASES ITEMS_PK ENABLED
/* disable foreign keys */
BEGIN
FOR r IN (
SELECT '"' || a.owner
|| '"."'
|| a.table_name
|| '"' AS full_table_name,
a.constraint_name
FROM user_constraints a
JOIN user_constraints b
ON ( a.r_constraint_name = b.constraint_name
AND a.r_owner = b.owner )
WHERE a.constraint_type = 'R'
AND b.status = 'ENABLED'
ORDER BY 1 ) LOOP
dbms_output.put_line ( 'Disable the constraint ' || r.constraint_name ||' (on table ' || r.full_table_name || ')' ) ;
dbms_utility.exec_ddl_statement ( 'alter table ' || r.full_table_name || ' disable constraint ' || r.constraint_name ) ;
END LOOP ;
END ;
/
Statement processed.
Disable the constraint ITEMS_FK (on table "XXX"."PURCHASES")
Disable the constraint CUSTOMERS_FK (on table "XXX"."PURCHASES")
/* status different between queries ????. Problem here!!!
*/
SELECT '"' || a.owner
|| '"."'
|| a.table_name
|| '"' AS full_table_name,
a.constraint_name,
b.status
FROM user_constraints a
JOIN user_constraints b
ON ( a.r_constraint_name = b.constraint_name
AND a.r_owner = b.owner )
WHERE a.constraint_type = 'R'
AND b.status = 'ENABLED'
ORDER BY 1
FULL_TABLE_NAME
CONSTRAINT_NAME STATUS
"XXX"."PURCHASES" ITEMS_FK ENABLED
"XXX"."PURCHASES" CUSTOMERS_FK ENABLED
select owner, table_name, r_constraint_name, status
from user_constraints
where constraint_type = 'R';
OWNER TABLE_NAME R_CONSTRAINT_NAME STATUS
XXX PURCHASES CUSTOMERS_PK DISABLED
XXX PURCHASES ITEMS_PK DISABLED
答案1
得分: 1
以下是翻译好的部分:
"Those are 2 different queries and they are correctly showing the results."
这是两个不同的查询,它们正确显示了结果。
"you're assuming that you are seeing the status of the foreign key constraint but... that is not the case. Add some additional columns to the query and it all becomes clear."
你假设你看到了外键约束的状态,但事实并非如此。向查询添加一些额外的列,一切都会变得清晰。
"The column b.status is the status of the referenced constraint, not the status of the foreign key constraint. The referenced constraint is the primary key value of the 2 tables and the status is "enabled" since you didn't touch those...."
列b.status是引用约束的状态,而不是外键约束的状态。引用约束是两个表的主键值,状态为"enabled",因为你没有对它们进行更改。
"To find referenced constraints, just use that other query you are showing"
要查找引用约束,只需使用你显示的另一个查询。
"But... I would not take this route. What if there is a constraint that is already disabled before you run your script ? That constraint will then be enabled again by your "enable" script. Much safer to create a table where you store the name of the constraints you have disabled so you know which ones to enable again afterwards."
但是...我不建议采取这种方法。如果在运行脚本之前已经有一个已禁用的约束呢?那么你的"enable"脚本将重新启用该约束。更安全的做法是创建一个表,其中存储你已禁用的约束的名称,这样你就知道哪些需要在之后重新启用。
英文:
Those are 2 different queries and they are correctly showing the results.
you're assuming that you are seeing the status of the foreign key constraint but... that is not the case. Add some additional columns to the query and it all becomes clear.
SELECT '"' || a.owner
|| '"."'
|| a.table_name
|| '"' AS full_table_name,
a.constraint_name,
a.status,
b.constraint_name,
b.table_name,
b.status
FROM user_constraints a
JOIN user_constraints b
ON ( a.r_constraint_name = b.constraint_name
AND a.r_owner = b.owner )
WHERE a.constraint_type = 'R'
AND b.status = 'ENABLED'
ORDER BY 1;
"ACDC"."PURCHASES" ITEMS_FK DISABLED ITEMS_PK ITEMS ENABLED
"ACDC"."PURCHASES" CUSTOMERS_FK. DISABLED CUSTOMERS_PK CUSTOMERS ENABLED
The column b.status
is the status of the referenced constraint, not the status of the foreign key constraint. The referenced constraint is the primary key value of the 2 tables and the status is "enabled" since you didn't touch those....
To find referenced constraints, just use that other query you are showing
select owner, table_name, r_constraint_name, status
from user_constraints
where constraint_type = 'R';
But... I would not take this route. What if there is a constraint that is already disabled before you run your script ? That constraint will then be enabled again by your "enable" script. Much safer to create a table where you store the name of the constraints you have disabled so you know which ones to enable again afterwards.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论