誕生日の年齢を計算するのに最適なコード (UDF) は? 非常に最適化されたコード。業界の最高の頭脳から得られる最良の答えを確認するためだけに、日付関連のコードを書くことができます。
日数で計算したい。
誕生日の年齢を計算するのに最適なコード (UDF) は? 非常に最適化されたコード。業界の最高の頭脳から得られる最良の答えを確認するためだけに、日付関連のコードを書くことができます。
日数で計算したい。
通常、スカラー関数のパフォーマンスはあまり良くありません。あなたが求めることを行うには、テーブル値関数として記述します。テーブル値関数には、適切にインライン展開されるという利点があります。
他の形式のクエリは、時間を浪費する関数の呼び出しであるため、大きな違いはありません。
CREATE FUNCTION dbo.fn_age(@birthdate datetime, @current_date datetime)
RETURNS TABLE
WITH SCHEMABINDING
AS
return (
select CAST(DATEDIFF(year, @birthdate, @current_date) - CASE WHEN((MONTH(@birthdate) * 100 + DAY(@birthdate)) > (MONTH(@current_date) * 100 + DAY(@current_date))) THEN 1 ELSE 0 END AS varchar(3)) + ' y, '
+ CAST(DATEDIFF(MONTH, DATEADD(year
, /* the year calculation*/ DATEDIFF(year, @birthdate, @current_date) - CASE WHEN((MONTH(@birthdate) * 100 + DAY(@birthdate)) > (MONTH(@current_date) * 100 + DAY(@current_date))) THEN 1 ELSE 0 END /* end of the year calculation*/
, @birthdate),
@current_date) AS varchar(2)) + ' m, '
+ CAST(DATEDIFF(day, DATEADD(month
, datediff(MONTH, DATEADD(year
, /* the year calculation*/ DATEDIFF(year, @birthdate, @current_date) - CASE WHEN((MONTH(@birthdate) * 100 + DAY(@birthdate)) > (MONTH(@current_date) * 100 + DAY(@current_date))) THEN 1 ELSE 0 END /* end of the year calculation*/
, @birthdate)
, @current_date)
, dateadd(year
, /* the year calculation*/ DATEDIFF(year, @birthdate, @current_date) - CASE WHEN((MONTH(@birthdate) * 100 + DAY(@birthdate)) > (MONTH(@current_date) * 100 + DAY(@current_date))) THEN 1 ELSE 0 END /* end of the year calculation*/
, @birthdate)
)
, @current_date) AS varchar(2)) + ' d' as [Age]
)
GO
この関数は次のように呼び出す必要があります。
SELECT Age = (SELECT Age FROM dbo.fn_age(birthDate, current_timestamp))
FROM Person
この問題を通常のスカラー関数として記述する場合、次のようなものを作成します。
CREATE FUNCTION dbo.fn_age_slow(@birthdate datetime, @current_date datetime )
RETURNS VARCHAR(10)
WITH SCHEMABINDING
AS
begin
return CAST(DATEDIFF(year, @birthdate, @current_date) - CASE WHEN((MONTH(@birthdate) * 100 + DAY(@birthdate)) > (MONTH(@current_date) * 100 + DAY(@current_date))) THEN 1 ELSE 0 END AS varchar(3)) + ' y, '
+ CAST(DATEDIFF(MONTH, DATEADD(year
, /* the year calculation*/ DATEDIFF(year, @birthdate, @current_date) - CASE WHEN((MONTH(@birthdate) * 100 + DAY(@birthdate)) > (MONTH(@current_date) * 100 + DAY(@current_date))) THEN 1 ELSE 0 END /* end of the year calculation*/
, @birthdate),
@current_date) AS varchar(2)) + ' m, '
+ CAST(DATEDIFF(day, DATEADD(month
, datediff(MONTH, DATEADD(year
, /* the year calculation*/ DATEDIFF(year, @birthdate, @current_date) - CASE WHEN((MONTH(@birthdate) * 100 + DAY(@birthdate)) > (MONTH(@current_date) * 100 + DAY(@current_date))) THEN 1 ELSE 0 END /* end of the year calculation*/
, @birthdate)
, @current_date)
, dateadd(year
, /* the year calculation*/ DATEDIFF(year, @birthdate, @current_date) - CASE WHEN((MONTH(@birthdate) * 100 + DAY(@birthdate)) > (MONTH(@current_date) * 100 + DAY(@current_date))) THEN 1 ELSE 0 END /* end of the year calculation*/
, @birthdate)
)
, @current_date) AS varchar(2)) + ' d'
end
GO
ご覧のとおり、テーブル値関数とまったく同じです。(場合によっては関数を高速化するスキーマバウンドでもあります)
最初の関数に対して次のスクリプトを実行する場合(私のPC上)
declare @a varchar(10) = ''
, @d datetime = '20120101'
, @i int = 1
, @begin datetime
select @begin = CURRENT_TIMESTAMP
while @i < 1000000
begin
select @a = Age
, @d = @begin - @i%1000
, @i += 1
from dbo.fn_age(@d, @begin)
end
select CURRENT_TIMESTAMP - @begin
GO
==> 00:00:07.920
declare @a varchar(10) = ''
, @d datetime = '19500101'
, @i int = 1
, @begin datetime
select @begin = CURRENT_TIMESTAMP
while @i < 1000000
begin
select @a = dbo.fn_age_slow(@d, @begin)
, @d = @begin - @i%1000
, @i += 1
end
select CURRENT_TIMESTAMP - @begin
==> 00:00:14.023
これは決して適切なベンチマークではありませんが、パフォーマンスの違いについては理解できるはずです。
これを試して。
CREATE TABLE patient(PatName varchar(100), DOB date, Age varchar(100))
INSERT INTO patient
VALUES ('d','06/02/2011',NULL)--,('b','07/10/1947',NULL),('c','12/21/1982',NULL)
;WITH CTE(PatName,DOB,years,months,days) AS
(SELECT PatName, DOB, DATEDIFF(yy,DOB,getdate()), DATEDIFF(mm,DOB,getdate()),
DATEDIFF(dd,DOB,getdate())
FROM patient)
SELECT PatName, DOB,
CAST(months/12 as varchar(5)) + ' Years' +
CAST((months % 12) as varchar(5)) + ' month/s ' +
CAST( CASE WHEN DATEADD(MM,(months % 12), DATEADD(YY,(months/12),DOB)) <= GETDATE()
THEN DATEDIFF(dd,DATEADD(MM,(months % 12), DATEADD(YY,(months/12),DOB)),GETDATE())
ELSE DAY(getdate())
END as varchar(5))+' days' AS Age
FROM CTE