2009-03-23 18 views
0

私は、多くのクライアントを追跡するMS-SQL Serverを持っています。誕生日がわかっている場合は、dayOfBirthという日時属性として格納されます。今私はクライアントの現在の年齢を追跡する別の属性年齢を持っていると思います。年齢はいつでも変わる可能性があるので、スクリプトがベストアイデアかもしれないと思った。年齢属性を正しく設定するにはどうすればよいですか?

私がやった最初のことは、誕生日をdatetimeとして指定した年齢を計算するストアドプロシージャを作成することでした。その後、私は非ヌルdayOfBirth属性を持つすべてのレコードを実行し、それに応じて満たされた年齢を更新し、別のスクリプトを作成し

USE [MyDB] 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 

CREATE PROCEDURE CalculateAge 
@dayOfBirth datetime, 
@age INT OUTPUT 
AS 

DECLARE @today datetime, @thisYearBirthDay datetime 
DECLARE @years int 

SET @today = GETDATE() 
SET @thisYearOfBirth = DATEADD(year, @dayOfBirth, @today), @dayOfBirth) 
SET @years = DATEDIFF(year, @dayOfBirth, @today) - (CASE WHEN @thisYearBirthDay > @today THEN 1 ELSE 0 END) 
SET @age = @years 

:ここに私が思い付いたものです。

USE [MyDB] 
GO 

DECLARE @age int; 
DECLARE @birth datetime; 
DECLARE @id intl 
DECLARE cursorQuery CURSOR FOR SELECT clientId FROM Clients WHERE dayOfBirth IS NOT NULL; 

OPEN cursorQuery 

FETCH NEXT FROM cursorQuery INTO @id 

WHILE @@FETCH_STATUS = 0 
BEGIN 
    SET @birth = (SELECT dayOfBirth from Kunden where [email protected]); 
    EXEC dbo.CalculateAge @birth, @age OUTPUT; 
    UPDATE Clients SET Age = @age WHERE clientId = @id; 
    FETCH NEXT FROM cursorQuery INTO @id 
END 

CLOSE cursorQuery 
DEALLOCATE cursorQuery 

上記のスクリプトを1日1回トリガーして年齢属性を設定します。今まで私が持っていたことだが、改善の余地が十分あるという気持ちがある。

**私はこのようなものになってしまったおかげで宋マイスター**

CREATE TABLE Client (

ID int identity(1,1) primary key, 
DOB datetime null, 
AGE as (case 
    when DOB is null then null 
    else DATEDIFF(YY,DOB,GETDATE()) - CASE WHEN (MONTH(GETDATE()) = MONTH(DOB) AND DAY(DOB) > DAY(GETDATE()) OR MONTH(GETDATE()) > MONTH(DOB)) THEN 1 ELSE 0 END 
    end 
    ) 
) 

答えて

2
代わりにトリガーを作成するの

と手動更新を行う、 最も簡単な方法は、Age呼ば計算フィールドを作成することです。

このように、Ageデータが同期していない(データは一貫しています)ため、トリガーまたは手動による更新が不要です。

人物の年齢を計算すると、下の図のように少し毛がかって見えます。ここで

alt text

テキストが

create table #Person (
ID  int identity(1, 1) primary key, 
DOB  datetime null, 
Age  as 
     (case 
       when DOB is null then null 
       --; Born today! 
       when datediff(d, DOB, getdate()) = 0 then 0 
       --; Person is not even born yet! 
       when datediff(d, DOB, getdate()) < 0 then null 
       --; Before the person's B-day month so calculate year difference only 
       when cast(datepart(m, getdate()) as int) > cast(datepart(m, DOB) as int) 
        then datediff(year, DOB, getdate()) 
       --; Before Person's b-day 
       else datediff(year, DOB, getdate()) - 1 
      end) 
) 
insert #Person select GetDate() 
insert #Person select null 
insert #Person select '12/31/1980' 

select * from #Person 

update #Person 
set  DOB = '01/01/1980' 
where ID = 2 

select * from #Person 
+0

+1すごくいいですが、計算に何か問題があると思います。まだ知っているかなりきちんとしたこと。私はそれに取り組んでいます。 – raupach

+0

@nooomiさて、スクリプトの全体はデモンストレーションのためのものであり、Ageのデフォルト値を設定する方法は、ヌルの代わりにそれをどのようにしたいかにかかっています – Sung

+0

@Sung私は知っており、非常に感謝しています:) – raupach

2

それは容易に計算し、上の変更されたとして、あなたが本当にデータベース内の年齢を格納すべきではありません毎日の基礎。

私は、生年月日のフィールドを保持し、必要に応じて年齢を計算することをお勧めします。年齢を他の属性と共に選択したい場合は、おそらく年齢を計算するユーザー定義関数を使用してビューを検討します。

には、以下のあなたがあなたの質問に答えて次のような何かを行うことができ、クエリ内で次に

CREATE FUNCTION age 
(
    @userId int 
) 
RETURNS int 
AS 
BEGIN 

    DECLARE @Result int 

    SELECT @Result = DATEDIFF(year, dateofBirth, getDate()) 
    FROM person 
    WHERE userId = @userId 

    RETURN @Result 

END 
GO 

SELECT *, 
     dbo.age(userId) as age 
FROM person 

を使用することができます例(未テスト)UDFでありますソートなどを行うと、データのビューを作成し、そのデータを表示することができます(テストされていない)

このビューを使用してクエリを実行したり、年齢に基づいてフィルタリングや並べ替えを行うパフォーマンスヒットがあります。年齢フィールドに基づいて定期的に並べ替え/並べ替えを行うと、インデックス付きのビューを作成できます。

+0

を使用しかし、どのように私は、ソートやフィルタリングを実装しますでしょうか?もし私が属性を持っていれば、私はそうすることができます。 'select * from clients where age = 30 and ...'のようなもの – raupach

+0

ありがとう+1、私はこれを試してみます。私が言ったように私は全くDBAではありません。私はこれらのものをHiberante経由で呼び出す必要があります。これがうまくいくかどうかわかりません。様子を見よう。 – raupach

0

ビューや機能を使用してください。正確に同じデータに基づいている2つのフィールドを保存しないでください。これを回避するには

関連する問題