2

私は以下のように2つのテーブルを持っています:

表 1、ユーザー一覧表:

Year  Month Id Type 
2010  3     1  A
2010  5     2  B
2010  10    1  A
2010  12    1  A

表 2 に、ユーザーの昇格履歴を示します。

Promote Date Id
2/20/2010    1
5/20/2010    1     (4/2010 the user got demoted, and after 1 month he got promote again)

これら 2 つのテーブルから、テーブル 1 と同様の結果テーブルを生成する必要がありますが、タイプ A のユーザーが過去 3 か月または特定の日付で 3 か月以上昇格したことを分類する列を追加します。たとえば、結果は次のようになります。

Year  Month Id | Duration
2010  3     1  | A < 3 months
2010  10    1  | A > 3 months
2010  12    1  | A > 3 months    

一般的な考え方は次のとおりです。

  • テーブル 1 の月の列と年の列を 2010 年 3 月のような日付形式に変換する必要があります。
  • 上記の日付 (2010 年 2 月) に最も近い昇格日で新しい換算値を減算して、ユーザーが昇格した日数を取得します。
  • 彼の昇進期間を分類するために90日と比較してください

私が現在立ち往生している2つの問題があります。

月の列と年の列を月/年の日付形式に変換する最良の方法がわかりません。

テーブル 1 から月/年の列を既に変換していると仮定して、Max 関数を使用してテーブル 2 から最も近い日付を取得します。私の知る限り、max 関数はパフォーマンスが良くないので、max を使用する代わりに他の解決策はありますか? mysql では Limit 1 を使えば簡単に解決できますが、SAS proc-sql は Limit に対応していません。proc-sql に limit に相当するものはありますか? 以下は現在考えているコードです。

PROC SQL;
Create table Result as SELECT table1.Year, table1.Month, table1.Code, 
(Case When table1.Type = "B" then "B"
When table1.Type = "A" AND (table1.Date - (Select MAX(table2.Date) From table2 Where table2.Date <= table1.Date AND table2.Id = table1.Id ) < 90) THEN "A < 3 months"
When table1.Type = "A" AND (table1.Date - (Select MAX(table2.Date) From table2 Where table2.Date <= table1.Date AND table2.Id = table1.Id ) >= 90) THEN "A > 3 months"
When table1.Type = "C" then "C"
end) as NewType
From table1
LEFT JOIN
// .... 
;
QUIT;

ご覧のとおり、table1 を他のテーブルと結合したままにする必要があるため、サブクエリを使用しますが、これもパフォーマンスが低下しますが、他の方法があるかどうかはわかりません。ヘルプとアドバイスをいただければ幸いです。

4

1 に答える 1

4

mdy()次のように、関数を使用して日付値を作成できます。

data have;
input Year  Month Id Type $;
datalines;
2010  3     1  A
2010  5     2  B
2010  10    1  A
2010  12    1  A
;
run;

data have;
set have;
format date date9.;
date = mdy(Month, 1, Year);
run;

日の値がないので、1 を使用しました (作成されるすべての日付は月の最初です)。

これで、2 つのテーブルを ID で結合し、最初のテーブルの日付と 2 番目のテーブルのプロモーション日付の差を計算できます。

proc sql;
    create table want as
    select *
          ,abs(date - promote) as diff
    from have as a
           left join
         prom as b
           on a.id = b.id;
quit;

その後、結果のテーブルを id、date、および diff で並べ替えます。

proc sort data=want;
by id date diff; 
run;

データセットをソートすると、次のようになります。

Year  Month  Id  Type   date       Promote    diff
---------------------------------------------------
2010  3      1   A      01MAR2010  20FEB2010  9
2010  3      1   A      01MAR2010  20MAY2010  80
2010  5      2   B      01MAY2010  .          .
2010  10     1   A      01OCT2010  20MAY2010  134
2010  10     1   A      01OCT2010  20FEB2010  223
2010  12     1   A      01DEC2010  20MAY2010  195
2010  12     1   A      01DEC2010  20FEB2010  284

最後のステップでは、データセットを反復処理し、diffすべての ID と日付の値の最初の値が 3 か月よりも小さいか、または 3 か月を超えているかどうかを確認します (90 日に対してチェックしたところ、intck関数も使用できます)。データセットを id、date、および diff でソートしたため、最初の行が日付に最も近いはずなのでoutput、最初の行のみになります。

data want2(keep = year month id type duration);
set want;
by date;

if first.date and Type = 'A' then do;


if diff lt 90 then do;
    duration = 'A < 3 months';
    output want2;
end;
if diff gt 90 then do;
    duration = 'A > 3 months';
    output want2;

    end;
end;
else if first.date  then do;
    duration = type;
    output want2;
end;

run;

output一部の行のみを保持するため、ステートメントが使用されます (グループごとに最初の行)。最後outputは、 A とは異なる型の値を持つ行も最終結果に残るようにそこにあります。

これが最終結果です。

Year    Month    Id    Type    duration
--------------------------------------------
2010    3        1     A       A < 3 months
2010    5        2     B       B
2010    10       1     A       A > 3 months
2010    12       1     A       A > 3 months
于 2013-03-02T11:15:43.357 に答える