0

誕生日の年齢を計算するのに最適なコード (UDF) は? 非常に最適化されたコード。業界の最高の頭脳から得られる最良の答えを確認するためだけに、日付関連のコードを書くことができます。

日数で計算したい。

4

3 に答える 3

0

通常、スカラー関数のパフォーマンスはあまり良くありません。あなたが求めることを行うには、テーブル値関数として記述します。テーブル値関数には、適切にインライン展開されるという利点があります。

他の形式のクエリは、時間を浪費する関数の呼び出しであるため、大きな違いはありません。

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

これは決して適切なベンチマークではありませんが、パフォーマンスの違いについては理解できるはずです。

于 2012-08-02T08:39:05.063 に答える
0

これを試して。

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
于 2012-08-02T05:57:22.930 に答える