数据库中有三个表:
即。 (也见图片)
tables: BusinessEntity Firm Customer
columns: CustomerID (PK)
BusinessEntityID(PK) --> BusinessEntityID (PK/FK) --> FirmID (FK)
我想要做的是每当要创建一个新的Customer行时: 要自动创建的新BusinessEntity行,然后将其BusinessEntityID值传递给(自动)新创建的Firm行,它将把自己的BusinessEntityID作为FirmID列传递给Customer表。
正如您所看到的那样,BusinessEntity行没有任何意义,除非它对应于公司(或其他实体),并且客户必须包含公司。
我创建了一个包含所有三个表的视图以及一个触发器来完成工作但没有成功。有什么建议吗?
表格:
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
坚定
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
客户
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
这里发生了一些奇怪的事。我创建了这个存储过程:
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)任何线索? (见图)
现在我创建了这个视图,将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。
答案 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.BusinessEntityID
是IDENTITY
- 如果要从BusinessEntity
获取其值,则不应该这样。 (您可以使用IDENTITY_INSERT
解决此问题,但在正确设计的数据库中,这不是必需的。)
另一件显而易见的事情是我们在BusinessEntity
中完全插入 no 业务数据(这就是为什么我们需要DEFAULT VALUES
语法) - 它只不过是一个超级一般的ID容器,所以它具有可疑的价值。然而,这演示了在具有依赖关系的多个表中插入行的一般技术。
如上所述,此存储过程始终会创建一个新的Firm
和BusinessEntity
以与Customer
一起使用。逻辑上,Firm
可以有多个Customer
,因此您可能希望其他存储过程为现有Customer
创建Firm
。这更简单,因为它只是INSERT
中Customer
的{{1}}。您可能希望首先使用单独的FirmID
存储过程,然后使用CreateFirm
为该公司添加客户。
答案 1 :(得分:0)
据我说,
这一切都取决于填充这3个表的方式和时间。 假设使用单个UI填充这三个表,然后
我会在一次交易中的单一过程中编写它们。
假设那些3表将在diff阶段填充,即diff UI,然后我在diff proc中编写它们,因为你已经定义了约束。
BTW所有3个表中rowguid的用途是什么。