2

我有以下问题要解决,我认为我需要一些帮助,因为我认为我认为可能的解决方案不正确:

我有一个带有identity列的 SQL Server 表。该表将存储当前数据以及历史数据,如下所述:

  1. 让我们假设下表:

    CREATE TABLE Patient 
    (PatientKey int IDENTITY(1,1) NOT NULL,
     PatientId int,
     UpdateDate datetime NOT NULL,
     UpdateUser int NOT NULL,
     RecordStatus tinyint NOT NULL)
    

PatientKey是主键,也是标识列。PatientId是唯一标识患者(当前记录以及历史记录)。UpdateDate是插入或更新患者的日期。UpdateUser用于插入或更新患者的用户的密钥。RecordStatus是表示一条记录的状态:0-历史,1-当前,2-已删除。

  1. 在上表中PatientId + RecordStatus = 1是唯一标识一个患者的当前记录。

  2. 当插入新患者时,会PatientKey为记录分配一个新患者(这由 SQL Server 引擎自动完成),并且PatientId还必须计算一个新患者并将其分配给记录。此外,RecordStatus设置为 1。

  3. 当现有患者被更新时,当前记录被更新为设置RecordStatus等于 0。然后,使用患者的修改数据插入新行。作为插入的一部分,PatientKey会为记录生成一个新的,但不会PatientId计算新的(即PatientId不会改变)。此外,RecordStatus设置为 1。

  4. 删除患者时,当前记录将更新为设置RecordStatus为 2。

问题在于 的计算PatientId。我正在考虑MAX(PatientId) + 1在存储过程中使用 a 来获取PatientId要分配给新记录的新记录,但这将是并发问题。如果多个用户同时创建一个新患者,则 SP 基本上会PatientId为他们两个计算相同的值,然后我会在表中结束两个不同的患者相同的PatientId.

然后,我正在考虑将更新放在 SQL Server 事务中以阻止表,但我认为这太过分了。此外,对于复杂的更新,我认为该表会被阻塞太久,并且其他创建患者的尝试会超时。有没有更好的方法来实现这一点?

谢谢。

4

3 回答 3

1

您可以只使用 PatientKey 作为 PatientId(在创建新患者时)并从那时起使用该 Id。

我会看到插入 SP 的工作方式如下:

-- Insert A new record with some values
INSERT INTO Patient (UpdateDate, UpdateUser, RecordStatus) 
SELECT @UpdateDate, @UpdateUser, @RecordStatus
     --if patient id is `not null` then just use a place holder value like 1 or 0

--update the new record with the UNIQUE patientKey
UPDATE Patient 
SET PatientId = PatientKey
WHERE PatientKey = SCOPE_IDENTITY() 

SELECT SCOPE_IDENTITY() --to return the new id 

您可以通过使用 Patient 表来完全解决此问题,该表为每位患者保存 1 条记录,并使用 patient_log 表来维护随时间的变化。使用更新前和删除触发器从 Patient 插入 Patient_log。这有很多好处,包括简化查询以获得当前状态,这可能是您执行的最常见的查询,表搜索的性能更快,因为表上没有那么多记录,降低复杂性和更好的数据约束,同时为您提供全面的可审计性,并能够通过一些巧妙的查询创建患者表在特定点的样子的快照。

如果您希望我详细说明这种方法,只需给我发电子邮件或发表评论。

于 2013-02-04T03:38:36.330 回答
1
/*

   this trigger exhibits the following behavior:
   for one or more inserts into the Patient table
   where the inserted record did not explicitly provide a value for PatientId
   the patient id is cacluated using the ROW_NUMBER function and
   an arbitrarily chosen seed value such that each new inserted row
   gets the next available patient id

   works for single or bulk inserts,
   only assigned patient ids to records who were inserted without one.

   NOTE 1: your inserts will probably need to be made within a transaction to avoid problems.
           i'll leave that for commentors to pick on ;)

   NOTE 2: you can then write an udpate trigger to ensure the immutability of PatientId

*/
CREATE TRIGGER [Rewards].[Trigger_Patient_Id]
   ON Patient
AFTER INSERT
AS
BEGIN
   SET NoCount ON

   /* create arbitrary seed value, just like an identity field */
   DECLARE @PatientIdSeed int = 512; 

   /* get the highest id currently in the database greater than the seed value */
   DECLARE @MaxPatientId int = (SELECT ISNULL(MAX(PatientId), @PatientIdSeed) FROM [Patient] WHERE PatientId > @PatientIdSeed) ;

   /* update the patient table... */
   UPDATE 
      [Patient]
   SET 
      /* ... getting new patient id ... */
      PatientId = NewPatientId
   FROM
      /* ... by joining the patient table ... */
      [Patient] AS Patient
      JOIN
         /* ... to this sub-query, that uses the ROW_NUMBER() function
                over the inserted table + MaxPatientId to get new PatientIds */
         (SELECT 
            inserted.Id,
            @MaxPatientId + ROW_NUMBER() OVER(ORDER BY inserted.Key) AS NewPatientId
          FROM 
            inserted
          /* remove this where clause if you wish to overwrite PatientId regardless of insert */
          WHERE
            inserted.PatientId IS NULL
         ) AS newinserts
         ON Patient.Key = newinserts.Key
END
于 2013-10-15T15:58:39.257 回答
1

为什么需要 PatientKey 列和 PatientId 列——它们不能组合为一个字段吗?由于您的表是 Patient,因此将主键设置为 PatientId 是有意义的,这可能是您的身份列。

假设不是,请考虑使用 aComputed Column作为您的 PatientId。

这是一个很好的参考指南:

http://msdn.microsoft.com/en-us/library/ms191250(v=sql.105).aspx

祝你好运。

于 2013-02-04T03:30:15.490 回答