如何自动创建行并将值传递给其他表

时间:2017-04-24 11:11:52

标签: sql-server database

enter image description here

数据库中有三个表:

  1. “BusinessEntity”,其标识列为“BusinessEntityID”作为主键(以及rowguid和ModifiedDate列)。
  2. “Firm”,它具有类似的标识列“BusinessEntityID”作为主键,它也是BusinessEntity.BusinessEntityID的外键(它与“BusinessEntity”表,FirmName,rowguid和ModifiedDate具有1对1的关系列)。
  3. “Customer”,其标识列为“CustomerID”作为主键,列“FirmID”为Firm .BusinessEntityID的外键(加上CustomerName,rowguid和ModifiedDate列)。
  4. 即。 (也见图片)

    tables:  BusinessEntity            Firm                          Customer
    columns:                                                         CustomerID (PK)
             BusinessEntityID(PK) -->  BusinessEntityID (PK/FK) -->  FirmID (FK)
    

    我想要做的是每当要创建一个新的Customer行时: 要自动创建的新BusinessEntity行,然后将其BusinessEntityID值传递给(自动)新创建的Firm行,它将把自己的BusinessEntityID作为FirmID列传递给Customer表。

    正如您所看到的那样,BusinessEntity行没有任何意义,除非它对应于公司(或其他实体),并且客户必须包含公司。

    我创建了一个包含所有三个表的视图以及一个触发器来完成工作但没有成功。有什么建议吗?

    表格:

    1. BusinessEntity

      CREATE TABLE [dbo ].[BusinessEntity](
         [BusinessEntityID] [int] IDENTITY(1,1) NOT NULL,
         [rowguid] [uniqueidentifier] NOT NULL,
         [ModifiedDate] [datetime] NOT NULL,
      
      CONSTRAINT [PK_BusinessEntity_BusinessEntityID] PRIMARY KEY CLUSTERED
      (
         [BusinessEntityID] ASC
      )
      ) ON [PRIMARY]
      GO
      
      ALTER TABLE [dbo].[BusinessEntity] ADD  CONSTRAINT [DF_BusinessEntity_rowguid]  
       DEFAULT (newid()) FOR [rowguid]
      GO
      
      ALTER TABLE [dbo ].[BusinessEntity] ADD  CONSTRAINT [DF_BusinessEntity_ModifiedDate]  
        DEFAULT (getdate()) FOR [ModifiedDate]
      GO
      
    2. 坚定

      CREATE TABLE [dbo].[Firm](
      [BusinessEntityID] [int] IDENTITY(1,1) NOT NULL,
      [FirmName] [nvarchar](30) NULL,
      [rowguid] [uniqueidentifier] NOT NULL,
      [ModifiedDate] [datetime] NOT NULL,
      
      CONSTRAINT [PK_Firm_BusinessEntityID] PRIMARY KEY CLUSTERED
         (
         [BusinessEntityID] ASC
         )
         ) ON [PRIMARY]
      GO
      
      ALTER TABLE [dbo].[Firm] ADD  CONSTRAINT [DF_Firm_rowguid]  
        DEFAULT (newid()) FOR [rowguid]
      GO
      
      ALTER TABLE [dbo].[Firm] ADD  CONSTRAINT [DF_Firm_ModifiedDate]  
        DEFAULT (getdate()) FOR [ModifiedDate]
      GO
      
      ALTER TABLE [dbo].[Firm]  WITH CHECK ADD  CONSTRAINT [FK_Firm_BusinessEntity_BusinessEntityID] FOREIGN KEY([BusinessEntityID])
        REFERENCES [dbo].[BusinessEntity] ([BusinessEntityID])
      GO
      
      ALTER TABLE [dbo].[Firm] CHECK CONSTRAINT [FK_Firm_BusinessEntity_BusinessEntityID]
      GO
      
    3. 客户

      CREATE TABLE [dbo].[Customer](
      [CustomerID] [int] IDENTITY(1,1) NOT NULL,
      [FirmID] [int] NULL,
      [CustomerName] [nvarchar](28) NULL,
      [rowguid] [uniqueidentifier] NOT NULL,
      [ModifiedDate] [datetime] NOT NULL, 
      
      CONSTRAINT [PK_Customer_CustomerID] PRIMARY KEY CLUSTERED
        (
        [CustomerID] ASC
        )
        ) ON [PRIMARY]
      GO
      
      ALTER TABLE [dbo].[Customer] ADD  CONSTRAINT [DF_Customer_rowguid]                  
         DEFAULT (newid()) FOR [rowguid]
      GO
      
      ALTER TABLE [dbo].[Customer] ADD  CONSTRAINT [DF_Customer_ModifiedDate]  
         DEFAULT (getdate()) FOR [ModifiedDate]
      GO
      
      ALTER TABLE [dbo].[Customer]  WITH CHECK ADD  CONSTRAINT [FK_Customer_Firm_FirmID] FOREIGN KEY([FirmID])
         REFERENCES [dbo].[Firm] ([BusinessEntityID])
      GO
      
      ALTER TABLE [dbo].[Customer] CHECK CONSTRAINT [FK_Customer_Firm_FirmID]
      GO
      
    4. 这里发生了一些奇怪的事。我创建了这个存储过程:

      CREATE PROCEDURE [dbo].[CreateFirmCustomer](@FirmName NVARCHAR(30), @CustomerName NVARCHAR(28)) AS 
      BEGIN;
      SET NOCOUNT ON;
      
      BEGIN TRANSACTION;
      
      INSERT BusinessEntity DEFAULT VALUES;
      DECLARE @BusinessEntityID INT = SCOPE_IDENTITY();
      
      SET IDENTITY_INSERT [dbo].[Firm] ON
      
      INSERT Firm(BusinessEntityID, FirmName)
      VALUES (@BusinessEntityID, @FirmName);
      
      SET IDENTITY_INSERT [dbo].[Firm] OFF
      
      INSERT Customer(FirmID, CustomerName)
      VALUES (@BusinessEntityID, @CustomerName);
      DECLARE @CustomerID INT = SCOPE_IDENTITY();
      
      SELECT @BusinessEntityID AS FirmID, @CustomerID AS CustomerID;
      
      COMMIT;
      END;
      
      GO
      

      当我运行它时,有时CustomerID列会获得BusinessEntityID列的值,它应该真正独立地自动生成。此外,BusinessEntityID列会自动生成奇怪的值,例如从值7跳到值1002.(BusinessEntityID是BusinessEntity.BusinessEntityID)任何线索? (见图)

      enter image description here

      现在我创建了这个视图,将Customers作为公司插入:

      CREATE VIEW [dbo].[vBusEntityFirmCustomer]
      AS
      SELECT dbo.Firm.FirmName, dbo.Customer.CustomerName
      FROM dbo.BusinessEntity INNER JOIN
           dbo.Firm ON dbo.BusinessEntity.BusinessEntityID = dbo.Firm.BusinessEntityID INNER JOIN
           dbo.Customer ON dbo.Firm.BusinessEntityID = dbo.Customer.FirmID
      GO
      

      此视图上的触发器:

      CREATE TRIGGER [dbo].[trg_FirmCustomer]
      ON [dbo].[vBusEntityFirmCustomer]
      INSTEAD OF INSERT
      AS
         exec [dbo].[CreateFirmCustomer]
      GO
      

      但是每次我输入一个新的FirmName CustomerName来插入一个新行时,我都会看到这条消息(见图):

      过程或函数'CreateFirmCustomer'需要参数'@FirmName',这是未提供的。 事实上,我确实提供了FirmName。

      enter image description here

2 个答案:

答案 0 :(得分:1)

逻辑上,按照设计,您必须首先创建BusinessEntity,然后创建Firm,然后创建Customer。在所有这些表中,您存储的唯一真正的信息是公司名称和客户名称 - 所有其余信息都由数据库派生和自动生成。我们可以将操作CreateCustomer封装在存储过程中:

CREATE PROCEDURE CreateCustomer(@FirmName NVARCHAR(30), @CustomerName NVARCHAR(28)) AS 
BEGIN;
    SET NOCOUNT ON;

    BEGIN TRANSACTION;

    INSERT BusinessEntity DEFAULT VALUES;
    DECLARE @BusinessEntityID INT = SCOPE_IDENTITY();

    INSERT Firm(BusinessEntityID, FirmName)
    VALUES (@BusinessEntityID, @FirmName);

    INSERT Customer(FirmID, CustomerName)
    VALUES (@BusinessEntityID, @CustomerName);
    DECLARE @CustomerID INT = SCOPE_IDENTITY();

    -- Return IDs of the newly created rows as the result set
    SELECT @BusinessEntityID AS FirmID, @CustomerID AS CustomerID;

    COMMIT;
END;

调用(例如)EXEC CreateCustomer 'Firm', 'Customer'。如果给定了表定义,则会失败,因为Firm.BusinessEntityIDIDENTITY - 如果要从BusinessEntity获取其值,则不应该这样。 (您可以使用IDENTITY_INSERT解决此问题,但在正确设计的数据库中,这不是必需的。)

另一件显而易见的事情是我们在BusinessEntity中完全插入 no 业务数据(这就是为什么我们需要DEFAULT VALUES语法) - 它只不过是一个超级一般的ID容器,所以它具有可疑的价值。然而,这演示了在具有依赖关系的多个表中插入行的一般技术。

如上所述,此存储过程始终会创建一个新的FirmBusinessEntity以与Customer一起使用。逻辑上,Firm可以有多个Customer,因此您可能希望其他存储过程为现有Customer创建Firm。这更简单,因为它只是INSERTCustomer的{​​{1}}。您可能希望首先使用单独的FirmID存储过程,然后使用CreateFirm为该公司添加客户。

答案 1 :(得分:0)

据我说,

这一切都取决于填充这3个表的方式和时间。 假设使用单个UI填充这三个表,然后

我会在一次交易中的单一过程中编写它们。

假设那些3表将在diff阶段填充,即diff UI,然后我在diff proc中编写它们,因为你已经定义了约束。

BTW所有3个表中rowguid的用途是什么。