3

アップデート

この新しいアプローチをINTNX使用すると、ループを使用してさらに単純化できると思います。配列を作成した場合:

data;
    array period [4] $ var1-var4 ('day' 'week' 'month' 'year');
run;

そして、各要素のループを作成しようとしました:

%MACRO sqlloop;
  proc sql;
    %DO k = 1 %TO dim(period);  /* in case i decide to drop something from array later */
      %LET bucket = &period(k)
      CREATE TABLE output.t_&bucket AS (
        SELECT INTX( "&bucket.", date_field, O, 'E') AS test FROM table);
    %END
  quit;
%MEND
%sqlloop

これはうまくいきませんが、私が望むアイデアを捉えています。INTX の各値に対してクエリを実行するだけです。それは理にかなっていますか?


以前の質問がいくつかあり、それらを 1 つにまとめます。他の人たちについて本当に役立つアドバイスをいくつかもらいました。うまくいけば、これがそれらを結び付けることができます.

SELECTSASproc sql;コードブロックにステートメントを入力するために動的文字列を作成する次の関数があります。

proc fcmp outlib = output.funcs.test;
    function sqlSelectByDateRange(interval $, date_field $) $;
        day = date_field||" AS day, ";
        week = "WEEK("||date_field||") AS week, ";
        month = "MONTH("||date_field||") AS month, ";
        year = "YEAR("||date_field||") AS year, ";

        IF interval = "week" THEN
            do;
                day = '';
            end;
        IF interval = "month" THEN
            do;
                day = '';
                week = '';
            end;
        IF interval = "year" THEN
            do;
                day = '';
                week = '';
                month = '';
            end;
        where_string = day||week||month||year;
    return(where_string);
    endsub;
quit;

これにより、必要な種類の文字列が作成されることを確認しました。

data _null_;
    q = sqlSelectByDateRange('month', 'myDateColumn');
    put q =;
run;

これにより、次の結果が得られます。

q=MONTH(myDateColumn) AS month, YEAR(myDateColumn) AS year,

これはまさに私が SQL 文字列にしたいことです。以前の質問から、この関数を a で呼び出す必要があると思いますMACRO。次に、次のようなものが必要です。

%MACRO sqlSelectByDateRange(interval, date_field);
  /* Code I can't figure out */
%MEND

PROC SQL;
  CREATE TABLE output.t AS (
    SELECT 
      %sqlSelectByDateRange('month', 'myDateColumn')
    FROM
      output.myTable
  );
QUIT;

コードでこのマクロを呼び出し、SQL SELECT 文字列の一部として解釈する方法がわかりません。他の回答で前の例のいくつかを試しましたが、うまくいきません。このより具体的な質問が、この欠けているステップを埋めるのに役立ち、将来それを行う方法を学ぶことができることを願っています.

4

3 に答える 3

3

2つのこと:

まず、%SYSFUNCを使用してカスタム関数を呼び出せるようにする必要があります。

%MACRO sqlSelectByDateRange(interval, date_field);
    %SYSFUNC( sqlSelectByDateRange(&interval., &date_field.) )
%MEND;

SYSFUNC を介して関数を呼び出す場合は、引用符を使用しないでください。また、SAS 9.2 までは FCMP 関数で SYSFUNC を使用することはできません。以前のバージョンを使用している場合、これは機能しません。

次に、select 句の末尾にコンマがあります。次のようなダミー列が必要になる場合があります。

PROC SQL;
  CREATE TABLE output.t AS (
    SELECT 
      %sqlSelectByDateRange('month', 'myDateColumn')
      0 AS dummy
    FROM
      output.myTable
  );
QUIT;

dummy(コンマは既にマクロに埋め込まれているため、 の前にコンマがないことに注意してください。)


アップデート

私は別の答えについてあなたのコメントを読みました:

また、さまざまな日付範囲に対して非常にアドホックに実行できるようにする必要があるため、誰かがリクエスト。

あなたがしていることを達成するためのより簡単な方法をお勧めできると思います。まず、日付と値を含む非常に単純なデータセットを作成します。日付は、さまざまな日、週、月、および年にまたがっています。

DATA Work.Accounts;

    Format      Opened      yymmdd10.
                Value       dollar14.2
                ;

    INPUT       Opened      yymmdd10.
                Value       dollar14.2
                ;

DATALINES;
2012-12-31  $90,000.00
2013-01-01 $100,000.00
2013-01-02 $200,000.00
2013-01-03 $150,000.00
2013-01-15 $250,000.00
2013-02-10 $120,000.00
2013-02-14 $230,000.00
2013-03-01 $900,000.00
RUN;

この関数を使用して 3 番目の列を作成し、「Opened」列を、、または(この完全なリストINTNXを参照)などの期間に丸めることができます。'WEEK''MONTH''YEAR'

%LET Period = YEAR;

PROC SQL NOPRINT;

    CREATE TABLE Work.PeriodSummary AS
    SELECT   INTNX( "&Period.", Opened, 0, 'E' ) AS Period_End FORMAT=yymmdd10.
           , SUM( Value )                        AS TotalValue FORMAT=dollar14.
    FROM     Work.Accounts
    GROUP BY Period_End
    ;

QUIT;

の出力WEEK:

Period_End   TotalValue
2013-01-05     $540,000
2013-01-19     $250,000
2013-02-16     $350,000
2013-03-02     $900,000

の出力MONTH:

Period_End   TotalValue
2012-12-31      $90,000
2013-01-31     $700,000
2013-02-28     $350,000
2013-03-31     $900,000

の出力YEAR:

Period_End   TotalValue
2012-12-31      $90,000
2013-12-31   $1,950,000
于 2013-07-15T16:24:40.693 に答える
2

Cyborg37 が言うように、おそらく関数の末尾のコンマを取り除く必要があります。ただし、これを行うために実際にマクロを作成する必要はありません。%SYSFUNC関数を直接使用するだけです。

proc sql;
  create table output.t as
  select %sysfunc( sqlSelectByDateRange(month, myDateColumn) )
         * /* to avoid the trailing comma */
  from output.myTable;
quit;

また、これはユーザー定義関数の巧妙な使い方ですが、なぜこれを行う必要があるのか​​はあまり明確ではありません。コードに潜在的な混乱を引き起こさない、より良い解決策がおそらく利用可能です。ユーザー定義のマクロなどのユーザー定義関数は作業を楽にしますが、管理上の悪夢を生み出すこともあります。

于 2013-07-15T16:39:42.400 に答える
1

エラーが発生する理由については、あらゆる種類の推測を行うことができますが、基本的には、このようにしないでください。とにかくデータステップになろうとしているだけのFCMP関数よりも、トラブルシューティングがはるかに簡単で実装がはるかに簡単なデータステップで、まさにあなたがやろうとしていることを行うことができます。

手順: 1. 可能な日付プルを含むデータセットを作成します。これを頻繁に使用する場合は、SAS AUTOEXEC で定義されている永続的なライブラリにこれを配置できます。2. 必要な日付文字列を取得するマクロを作成します。3. 必要に応じて、PROC FCMP を使用して、RUN_MACRO を使用してこれを関数スタイルのマクロにします。4. その場合は、%SYSFUNC を使用して呼び出します。

これを行うものは次のとおりです。

1:

data pull_list;
infile datalines dlm='|';
length query $50. type $8.;
input type $ typenum query $;
datalines;
day|1|&date_field. as day
week|2|week(&date_field.) as week
month|3|month(&date_field.) as month
year|4|year(&date_field.) as year
;;;;
run;

2:

%macro pull_list(type=,date_field=);
%let date_field = datevar;
%let type = week;
proc sql noprint;
select query into :sellist separated by ',' 
from pull_list
where typenum >= (select typenum from pull_list where type="&type.");
quit;
%mend pull_list;

3:

proc fcmp outlib = work.functions.funcs;
   function pull_list(type $,date_field $) $;
      rc = run_macro('pull_list', type,date_field);
      if rc eq 0 then return("&sellist.");
      else return(' ');
   endsub;
run;

4:

data test;
input datevar 5.;
datalines;
18963
19632
18131
19105
;;;;
run;
option cmplib = (work.functions);

proc sql;
select %sysfunc(pull_list(week,datevar)) from test;
quit;

これの大きな利点の 1 つは、関数のコードを気にせずに型を追加できることです。pull_list に行を追加するだけで機能します。そのように設定したい場合は、typenum に 1,2,3,4 以外のものを使用することをお勧めします. 、それは 2 から 3 の間であり、25 は 2.5 よりも人々が考えるのが簡単です)。その pull_list データセットを作成し、それをすべてのユーザーが使用できるネットワーク ドライブに置き (自分以外の誰かが使用する場合は、使用しない場合は個人用に)、そこから移動します。

于 2013-07-15T17:27:44.487 に答える