3

我正在使用 SQL Server 2008 R2、C# 和 ASP.Net。我有一个表,它有一个由票号组成的复合主键,以及该票在表中出现的次数。通过 C# 代码计算出票频率:

VTTTickets.InsertParameters[0].DefaultValue = VTTTTicketNoBox.Text;
string CommString = "SELECT COUNT(*) FROM [Tickets] WHERE [Ticket_No] = " + 
VTTTTicketNoBox.Text;
string ConnString = ConfigurationManager.ConnectionStrings[1].ConnectionString;
OdbcConnection Conn = new OdbcConnection(ConnString);
Conn.Open();
OdbcCommand FooCommand = newOdbcCommand(CommString,Conn);
int FooVal = Convert.ToInt32(FooCommand.ExecuteScalar()) + 1;
VTTTickets.InsertParameters[1].DefaultValue = Convert.ToString(FooVal);
VTTTTicketNoBox.Text = "";
Conn.Close();

我的表约束/等代码

CONSTRAINT [PK_Tickets] PRIMARY KEY CLUSTERED 
([Ticket_No] ASC, [Ticket_Sub_No] ASC)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = ON,
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY],
CONSTRAINT [Unique_Ticket_No] UNIQUE NONCLUSTERED 
([Ticket_No] ASC)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = ON,     
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY],
) ON [PRIMARY]
GO

唯一约束的原因是因为主复合键的那部分也是另外两个表的外键。我不断遇到的错误是当它对我大喊大叫时,因为唯一受约束的列中存在重复值。一旦一切从开发转移到生产,这可能会发生,因为可能会重新提交票证。

有没有办法在没有唯一键约束的情况下制作外键?如果没有,我该如何解决这个问题?

4

1 回答 1

5

这是我们在编程中经常遇到的情况之一。Technology_A 不会让我做 Operation_B,但应该!然后,在用头撞墙一段时间后,我们放弃了(或前往 Stackoverflow)。我们这样做是因为我们没有按照预期使用技术(没关系,这就是我们学习的方式!)

这里的问题是您的数据库架构。

您正试图用一张桌子做太多事情。您不应将票证(同一张票证可能存在多次)存储在您正在跟踪的发生次数的同一张表中。

在我看来,有两种很好的策略来纠正这种情况。首先,我将创建一个带有单列主键的票据表。然后,我将创建一个存储票证的每个实例的表。

在此处输入图像描述

示例:Ticket43 已关闭,但重新打开并再次关闭。这意味着(如果我没看错你的问题),这张票有两个实例。这意味着它将在您的原始表中有两个条目,但在我提出的新架构中,它会在门票中有一个条目,在 Ticket_Instances 中有两个条目。

注意:您需要确保将票据信息存储在 Ticket 中的实例之间永远不会更改,并将特定于实例的 Ticket 信息存储在 Ticket_Instances 中。

要记录 Ticket Counts,我要做的第一件事就是简单地编写一个视图或一段 SQL,如下所示:

SELECT
  count(*) as TicketCount,
  TicketID
FROM
  Ticket_Instances as TI
GROUP BY
  TicketID

如果您不想按需计算,那么我建议使用:

  • ASP.NET 缓存(运行上面的 SQL,将其塞入缓存,TTL 为 10 分钟)
  • 使用由触发器填充的 Ticket_Counts 表

我怀疑你会更喜欢那里的选项 2(尽管我会使用选项 1)。

触发方式:

假设 Ticket_Instances 可能永远不会被删除,您只需要一个插入触发器。您将在插入时在 Ticket_Instances 表上创建一个触发器,该触发器 SQL 将执行以下操作:

  • 如果 Ticket_Counts 中不存在 TicketID,则将 TicketID 插入 Ticket_Counts,TicketCount 为 0
  • 然后,将 Ticket_Counts 中的 TicketID 的 TicketCount 加 1

使用此方法,您只需通过 TicketID 访问 Ticket_Counts 即可获取该特定 Ticket 的出现次数。

我想你会发现一旦你更新你的模式,你的约束错误就会消失。

于 2011-05-08T01:37:49.853 回答