SQL/ORACLE-使用来自其他表的两列的外键

SQL/ORACLE-使用来自其他表的两列的外键,sql,oracle,Sql,Oracle,我试图在SQL*Plus中创建一个表,该表引用另一个表中的两列。比如说, 如果表A看起来像这样: CREATE TABLE Customers (Customer_ID int NOT NULL PRIMARY KEY, NAME Varchar(30) NOT NULL, PHONE Varchar(12) NOT NULL, OUTSTANDING_FEES Varchar(10) NULL); CREATE TABLE Customer_Fees (Fee_ID int NOT NUL

我试图在SQL*Plus中创建一个表,该表引用另一个表中的两列。比如说,

如果表A看起来像这样:

CREATE TABLE Customers
(Customer_ID int NOT NULL PRIMARY KEY, 
NAME Varchar(30) NOT NULL,
PHONE Varchar(12) NOT NULL,
OUTSTANDING_FEES Varchar(10) NULL);
CREATE TABLE Customer_Fees
(Fee_ID int NOT NULL PRIMARY KEY,
FEE_TYPE Varchar(20) NOT NULL,
AMOUNT Varchar(10) NOT NULL,
CUSTOMER_ID int NOT NULL);
如果我的表B看起来像这样:

CREATE TABLE Customers
(Customer_ID int NOT NULL PRIMARY KEY, 
NAME Varchar(30) NOT NULL,
PHONE Varchar(12) NOT NULL,
OUTSTANDING_FEES Varchar(10) NULL);
CREATE TABLE Customer_Fees
(Fee_ID int NOT NULL PRIMARY KEY,
FEE_TYPE Varchar(20) NOT NULL,
AMOUNT Varchar(10) NOT NULL,
CUSTOMER_ID int NOT NULL);
我想用表B中的金额填充表A中的未付费用,其中客户ID在表中匹配。出于我的目的,我可以假设表B中的任何单个客户ID在表中只出现一次

我尝试创建这两个表,表A的“未付费用”字段为空,然后将其设置为引用表B的“金额”字段的外键,但它不起作用,因为我需要确保它还交叉引用两个表中的“客户ID”字段


如果你能帮忙,谢谢你

不能从其他表在非主列上创建外键。 您必须在FEE_ID上创建FK

CREATE TABLE Customers (
Customer_ID int NOT NULL PRIMARY KEY, 
NAME Varchar(30) NOT NULL,
PHONE Varchar(12) NOT NULL,
OUTSTANDING_FEES Varchar(10) FOREIGN KEY REFERENCES Customer_Fees(FEE_ID)
);
您可以在select子句中使用AMOUNT字段

Select A.Customer_ID,B.AMOUNT from Customers A Join Customer_Fees B
on A.OUTSTANDING_FEES = B.FEE_ID

不能从其他表在非主列上创建外键。 您必须在FEE_ID上创建FK

CREATE TABLE Customers (
Customer_ID int NOT NULL PRIMARY KEY, 
NAME Varchar(30) NOT NULL,
PHONE Varchar(12) NOT NULL,
OUTSTANDING_FEES Varchar(10) FOREIGN KEY REFERENCES Customer_Fees(FEE_ID)
);
您可以在select子句中使用AMOUNT字段

Select A.Customer_ID,B.AMOUNT from Customers A Join Customer_Fees B
on A.OUTSTANDING_FEES = B.FEE_ID

问题中提出的数据模型有几个问题


  • 将未付费用和金额定义为
    varchar2
    列是不好的数据建模,因为两者都是数字(货币)值。好的做法是始终为我们建模的属性使用最合适的数据类型

  • 在未付费用和金额之间构建外键是错误的,因为它们不是唯一标识符。一个客户所欠的金额可以与任何其他客户(甚至所有客户)所欠的金额相同(在学期开始时,所有学生都欠相同金额的学费)。因此,只需要一个“引用两个表中的CUSTOMER_ID字段”的外来字段

  • 数据模型没有提供任何属性,允许我们区分已支付的费用和未支付的费用

  • 提问者表示,“我可以假设表B中的任何单个客户ID在表中只出现一次”,但在现实生活中,我们希望客户有多个未付和已付的费用记录。为什么不模仿呢?否则,如果客户和费用之间确实存在1:1的关系,则不需要两个表

  • 这是一个改进的模型。它对货币值使用适当的数据类型;它使用CUSTOMER_ID在两个表之间强制执行外键;因此,它支持客户和费用之间的一对多关系;最后,它跟踪已支付和未支付的费用

    create table customers
    ( customer_id integer      not null constraint cust_pk primary key
    , name        varchar2(30) not null
    , phone       varchar2(12) not null
    )
    /
    
    create table customer_fees
    ( fee_id       integer      not null constraint fees_pk primary key
    , fee_type     varchar2(20) not null
    , amount       number       not null
    , invoice_date date         not null
    , paid_date    date             null
    , customer_id  integer      not null constraint fees_cust_fk references customers 
    )
    /
    
    啊,但是未付的学费呢?嗯,这些信息可以从两个表中的数据推导出来。编写此查询有多种方法,这种方法只是一种选择:

    select cust.customer_id
           , cust.name
           , cust.phone
           , fees.outstanding_fees
    from   customers cust
           left outer join 
            ( select fees.customer_id
                   , sum(case when fees.paid_date is null then fees.amount 
                         else 0 end) as outstanding_fees
              from customer_fees fees
              group by fees.customer_id ) fees on fees.customer_id = cust.customer_id
    
    / 
    

    一般来说,最好按需计算总价值,而不是在每笔交易中重新计算。它的扩展性更好,当然是OLTP的数据量;数据仓库的物理特性是不同的,但我认为这不是我们在本例中要处理的

    问题中提出的数据模型存在一些问题


  • 将未付费用和金额定义为
    varchar2
    列是不好的数据建模,因为两者都是数字(货币)值。好的做法是始终为我们建模的属性使用最合适的数据类型

  • 在未付费用和金额之间构建外键是错误的,因为它们不是唯一标识符。一个客户所欠的金额可以与任何其他客户(甚至所有客户)所欠的金额相同(在学期开始时,所有学生都欠相同金额的学费)。因此,只需要一个“引用两个表中的CUSTOMER_ID字段”的外来字段

  • 数据模型没有提供任何属性,允许我们区分已支付的费用和未支付的费用

  • 提问者表示,“我可以假设表B中的任何单个客户ID在表中只出现一次”,但在现实生活中,我们希望客户有多个未付和已付的费用记录。为什么不模仿呢?否则,如果客户和费用之间确实存在1:1的关系,则不需要两个表

  • 这是一个改进的模型。它对货币值使用适当的数据类型;它使用CUSTOMER_ID在两个表之间强制执行外键;因此,它支持客户和费用之间的一对多关系;最后,它跟踪已支付和未支付的费用

    create table customers
    ( customer_id integer      not null constraint cust_pk primary key
    , name        varchar2(30) not null
    , phone       varchar2(12) not null
    )
    /
    
    create table customer_fees
    ( fee_id       integer      not null constraint fees_pk primary key
    , fee_type     varchar2(20) not null
    , amount       number       not null
    , invoice_date date         not null
    , paid_date    date             null
    , customer_id  integer      not null constraint fees_cust_fk references customers 
    )
    /
    
    啊,但是未付的学费呢?嗯,这些信息可以从两个表中的数据推导出来。编写此查询有多种方法,这种方法只是一种选择:

    select cust.customer_id
           , cust.name
           , cust.phone
           , fees.outstanding_fees
    from   customers cust
           left outer join 
            ( select fees.customer_id
                   , sum(case when fees.paid_date is null then fees.amount 
                         else 0 end) as outstanding_fees
              from customer_fees fees
              group by fees.customer_id ) fees on fees.customer_id = cust.customer_id
    
    / 
    

    一般来说,最好按需计算总价值,而不是在每笔交易中重新计算。它的扩展性更好,当然是OLTP的数据量;数据仓库的物理特性是不同的,但我认为这不是我们在本例中要处理的

    您不能创建外键引用到非主键列。随着时间的推移,每个客户肯定会收取很多费用;这些钱会在某个时候支付吗?所以这似乎有缺陷。如果您想查看客户的未付费用,则需要查看并汇总所有费用和付款。尝试在父表中记录结果(例如,在添加或支付费用时通过触发器)可能仍然是不明智的。拥有一个连接相关表的视图会更简单/更安全,这些表总是最新的。@tejash-“您不能创建外键引用到非主键列”。不太准确。我们可以构建引用唯一约束的外键,这比引用主键不常见,但它有自己的用例<