0

I need to give a report to a group of people summarizing each persons information, but only revealing the name of the person each report is going to. What I have is:

アリス 4 15% 8 20%
ボブ 8 30% 6 15%
キャロル 4 15% 8 20%
デイブ 4 15% 8 20%
エリン 4 15% 8 20%

私が欲しいのは:

Alice のまとめ
Alice 4 15% 8 20%
Person2 8 30% 6 15%
Person3 4 15% 8 20%
Person4 4 15% 8 20%
Person5 4 15% 8 20%

Bob の要約
Person1 4 15% 8 20%
Bob 8 30% 6 15%
Person3 4 15% 8 20%
Person4 4 15% 8 20%
Person5 4 15% 8 20%

など。

私はいくつかのことを試しましたが、一人一人番号を取得することをあきらめました。私の最新の試みは次のとおりです。

proc sql;
create table Distinct_People
as select distinct(Name)
from have;
quit;

data People;
set Distinct_People end=no_more;
call symputx('Person'||left(_n_), Name);
if no_more then call symputx('NumPeople', _n_);
run;
quit;

%macro Loop;
%do j=1 %to &NumPeople;
%let Person=Person&j;
data want;
set have;
if Name="&&Person&j" then "&&Person&j";
else "Person";
run;
%end;
%mend Loop;
%Loop;

私はおそらく上記を台無しにしたことを知っていますが、proc sqlまたはdataステップでSAS/SQLを使用してこれを行う方法を実際に理解する必要があります。

ありがとうございました!

4

2 に答える 2

0

proc sql匿名の人の名前と番号を取得するためのサブクエリを含むユニオンクエリを使用したソリューションを部分的に持っています。

しかし、お気づきのように、各人は各選択クエリに手動で入力されています。例に示した5人ではなく、データセット内のたとえば200人に対してこれを行うのは嫌です。1 つの可能性は、ユニオンの選択クエリをミラーリングする挿入クエリを実行することです。

proc sql;

create table AnonymousReport As
    SELECT CASE WHEN t1.name = 'Alice' THEN t1.name ELSE CATS('Person',
           (SELECT count(name) + 1 From have t2 
            WHERE t2.name <= t1.name AND t1.name ne t2.name)) END As RptName, 
           t1.Col1Number, t1.Col1Pct, t1.Col2Number, t1.Col2Pct, 'Alice' As ReportToWhom
    FROM have t1

    UNION ALL

    SELECT CASE WHEN t1.name = 'Bob' THEN t1.name ELSE CATS('Person',
           (SELECT count(name) + 1 From have t2 
            WHERE t2.name < t1.name AND t1.name ne t2.name)) END As RptName, 
            t1.Col1Number, t1.Col1Pct, t1.Col2Number, t1.Col2Pct, 'Bob' As ReportToWhom
    FROM have t1

    UNION ALL

    SELECT CASE WHEN t1.name = 'Carol' THEN t1.name ELSE CATS('Person',
           (SELECT count(name) + 1 From have t2 
            WHERE t2.name < t1.name AND t1.name ne t2.name)) END As RptName, 
            t1.Col1Number, t1.Col1Pct, t1.Col2Number, t1.Col2Pct, 'Carol' As ReportToWhom
    FROM have t1

    UNION ALL

    SELECT CASE WHEN t1.name = 'Dave' THEN t1.name ELSE CATS('Person',
           (SELECT count(name) + 1 From have t2 
            WHERE t2.name < t1.name AND t1.name ne t2.name)) END As RptName, 
    t1.Col1Number, t1.Col1Pct, t1.Col2Number, t1.Col2Pct, 'Dave' As ReportToWhom
    FROM have t1

    UNION ALL

    SELECT CASE WHEN t1.name = 'Erin' THEN t1.name ELSE CATS('Person', 
           (SELECT count(name) + 1 From have t2 
            WHERE t2.name < t1.name AND t1.name ne t2.name)) END As RptName, 
    t1.Col1Number, t1.Col1Pct, t1.Col2Number, t1.Col2Pct, 'Erin' As ReportToWhom
    FROM have t1;

quit;

出力データセット。ここから、最後の列 ReportToWhom ごとに各人の個別レポートをエクスポートします

RptName     Col1Number  Col1Pct Col2Number  Col2Pct    ReportToWhom
Alice       4           15%              8      20%    Alice
Person2     8           30%              6      15%    Alice
Person3     4           15%              8      20%    Alice
Person4     4           15%              8      20%    Alice
Person5     4           15%              8      20%    Alice
Person1     4           15%              8      20%    Bob
Bob         8           30%              6      15%    Bob
Person3     4           15%              8      20%    Bob
Person4     4           15%              8      20%    Bob
Person5     4           15%              8      20%    Bob
...

考えられる解決策の 1 つは、連結された挿入 SQL クエリをデータセットのすべての行で使用することです。

data concat;
    set have;
    length reptAll $3200;
    by name;
    retain reptAll;

    if first.name then reptAll = "";
    unionSQL = "INSERT INTO AnonymousReport (RptName, Col1Number, Col1Pct, Col2Number, Col2Pct, ReportToWhom)
        SELECT CASE WHEN t1.name = '" || name || "' THEN t1.name 
        ELSE CATS('Person', (SELECT count(name) + 1 From have t2 
        WHERE t2.name <= t1.name AND t1.name ne t2.name)) END As RptName, 
        t1.Col1Number, t1.Col1Pct, t1.Col2Number, t1.Col2Pct, '" || name || "' As ReportToWhom
        FROM have t1";

    reptAll =  catx('; ', reptAll, unionSQL) ;

    call symput('query', reptAll);
    if last.name then output;
run;

そして、文字列をproc sqlマクロに渡します:

%macro runsql;
    proc sql;   
        &query; 
    quit;
%mend runsql;

%runsql;

pasteR では、 / forloop/関数を使用して数秒でこれを実行できましapplyたが、SAS 構文は別世界です!

于 2015-10-06T23:43:23.843 に答える
0

マクロで何をしようとしているのか正確にわからず、結果の何が問題なのか正確にわからなくても、コード内の 3 つのエラーを見つけることができます。

1.

data person;

ループでは、ループを実行するたびに、データセットの人物を上書きします。次のループでは、上書きされたデータセットに再度アクセスします。したがって、最後にはデータセットが 1 つしかなく、毎回上書きしたため、名前として personx しか残っていません。data person&j;そのため、すべての人に対して単一のデータセットを取得するように記述する必要があります。

2.

 set person;

データセット担当者とは? あなたの例では以前にそれを定義していませんでした。あなたがやろうとしていることを理解している限り、set have;ここで使用する必要があります。

3.

あなたは名前を上書きするのを忘れました

 if Name="&&Person&j" then 
 name ="&&Person&j";
 else 
 name ="&Person";

またはより単純なバージョン:

if Name ne "&&Person&j" then 
   name ="&Person";

4.

エラーではありませんが、data _null_;代わりに を使用する必要がありますdata people;。これは、このデータステップを使用していくつかのマクロ変数を生成し、出力をもう使用しないためです。したがって、ここで新しいデータセットを作成する必要はありません。データステップの後の終了は廃止されました...


編集:

今日テストしましたが、このコードは間違いなく機能しています。それでもエラーが発生する場合は、タイプミスがあるか、環境に問題があると思います。

data have;

input name $ nr1 nr2 $ nr3 n4 $;
 datalines;
 Alice 4 15% 8 20%
Bob 8 30% 6 15%
Carol 4 15% 8 20%
Dave 4 15% 8 20%
Erin 4 15% 8 20% 
;
run;

proc sql;
create table Distinct_People
as select distinct(Name)
from have;
quit;

data _null_;
set Distinct_People end=no_more;
call symputx('Person'||left(_n_), Name);
if no_more then call symputx('NumPeople', _n_);
run;
quit;

%macro Loop;
%do j=1 %to &NumPeople;
data want&j;
set have;
if Name ne "&&Person&j" then name = cat("Person",_n_);
run;
%end;
%do j=1 %to &NumPeople;
proc print data=want&j; 
title1 " &&Person&j.'s Summary";
run;
%end;
%mend Loop;
%Loop;

結果:

ここに画像の説明を入力

于 2015-10-06T20:45:19.833 に答える