查询外键不同结果

huangapple go评论57阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2023年5月10日 23:50:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/76220433.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定