2

次の問題を解決する必要があります。考えられる解決策として考えていることが正しいとは思わないため、助けが必要だと思います。

列を持つ SQL Server テーブルがありidentityます。このテーブルには、以下で説明するように、現在のデータと履歴データが格納されます。

  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主キーであり、ID 列でもあります。PatientId患者を一意に識別することです(現在の記録と過去の記録)。UpdateDate患者が挿入または更新された日付です。UpdateUser患者を挿入または更新したユーザーのキーです。RecordStatusはレコードのステータスを示します: 0 - 履歴、1 - 現在、2 - 削除済み。

  1. 上のテーブルPatientId + RecordStatus = 1では、患者の現在のレコードを一意に識別します。

  2. 新しい患者が挿入されると、新しい患者がPatientKeyレコードに割り当てられ (これは SQL Server エンジンによって自動的に行われます) 、新しい患者PatientIdも計算されてレコードに割り当てられる必要があります。また、RecordStatusは 1 に設定されます。

  3. 既存の患者が更新されると、現在のレコードが更新されRecordStatusて 0 に設定されます。次に、患者の変更されたデータを含む新しい行が挿入されます。挿入の一部としてPatientKey、レコードに対して new が生成されますが、newPatientIdは計算されません (つまり、PatientId変更されません)。また、RecordStatusは 1 に設定されます。

  4. 患者が削除されると、現在のレコードが更新されRecordStatusて 2 に設定されます。

問題は の計算にありPatientIdます。MAX(PatientId) + 1新しいレコードに割り当てる新しいを取得するためにストアド プロシージャでa を使用することを考えていPatientIdますが、これは同時実行性に問題があります。複数のユーザーが同時に新しい患者を作成している場合、SP は基本的PatientIdにそれらのうちの 2 人に対して同じものを計算し、テーブルに 2 人の異なる患者を同じPatientId.

次に、SQL Server トランザクションに更新を入れてテーブルをブロックすることを考えていましたが、これでは多すぎると思います。その上、複雑な更新の場合、テーブルがブロックされすぎて、患者を作成する他の試みがタイムアウトになると思います。これを実装するより良い方法はありますか?

ありがとう。

4

3 に答える 3

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 列が必要なのですか? これらを 1 つのフィールドとして結合することはできませんか? あなたのテーブルは患者であるため、主キーを患者 ID として持つことは理にかなっています。これは ID 列になる可能性があります。

Computed Columnそうでない場合は、PatientId にa を使用することを検討してください。

ここに良いリファレンスガイドがあります:

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

幸運を。

于 2013-02-04T03:30:15.490 に答える
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 

この問題は、患者ごとに 1 つのレコードを保持する Patient テーブルを用意し、patient_log テーブルを使用して経時的な変更を維持することで、完全に解決できます。更新前および削除トリガーを使用して、Patient から Patient_log に挿入します。これには、おそらく実行する最も一般的なクエリである現在の状態を取得するための単純化されたクエリ、テーブルにそれほど多くのレコードがないためテーブルシークのパフォーマンスが向上する、複雑さが軽減され、データの制約が改善されるなど、多くの利点があります。完全な監査可能性と、巧妙なクエリを使用して特定の時点で患者テーブルがどのように見えるかのスナップショットを作成する機能を提供します。

このアプローチについて詳しく説明してほしい場合は、私にメールするか、コメントを残してください。

于 2013-02-04T03:38:36.330 に答える