SAS' Merge has one END only. The indicated variable is set to 1 when both files are at end of file...
data Work.Updated (keep = Store Date Cost) ;
merge Work.Master (rename = (Cost = m_Cost) in=in_master)
Work.Trans (rename = (Cost = t_Cost) in=in_trans )
end=eof_both ;
by Store Date;
...and later...
if (eof_both) then do;
* do eof stuff ;
end;
run;
Wednesday, January 23, 2013
SAS: Setting a macro variable to value of SYSCC, which is itself a macro variable.
Here's how to set a SAS macro variable to the value of SYSCC, which is itself a macro variable:
%if (&SYSCC ne 0) %then %do;
%let ERR_LVL = %sysevalf(&SYSCC);
%end;
%if (&SYSCC ne 0) %then %do;
%let ERR_LVL = %sysevalf(&SYSCC);
%end;
Tuesday, January 22, 2013
SAS: Left-align a macro value
I write various data to a process log as name-value pairs. Sometimes the "values" are character and sometimes they are numeric, so they are defined as character in the database. I want the "values" to be left-aligned regardless of type. The name-value pairs are appended to the log via a macro which uses an INSERT statement within PROC SQL. For some unknown reason, I was unable to use trim(left(x)) in the INSERT statement. But I stumbled upon a format option which allows left / right / center justification:
%append_to_process_log("#output", put(&OUT, 10. -l));
%append_to_process_log("#output", put(&OUT, 10. -l));
SAS: Redirecting the WORK files
Here's how to send SAS WORK files to a different drive / folder.
Edit the file (your drive may differ...)
Add these two lines (the first of the two may already be there; if so then the line after as shown here:0
Note there is no semi-colon on the -WORK line, which is unlike most SAS stuff.
Edit the file (your drive may differ...)
E:\SAS\Config\Lev1\SASApp\sasv9_usermods.cfg
Add these two lines (the first of the two may already be there; if so then the line after as shown here:0
/* Setup the default SAS System user work folder */
-WORK "J:\SASWORK"
Note there is no semi-colon on the -WORK line, which is unlike most SAS stuff.
Monday, January 21, 2013
SAS: log1px funtion
Here's
some SAS information I found curious. I am currently taking a time series course, and in the first homework assignment we are asked
to calculate the log returns as lnreturn = log(ret + 1). This must be a
common operation, because SAS has a builtin function for that purpose.
The function is log1px and is used as follows: lnreturn = log1px(ret);
Big deal, right? I mean it's not as if the other way (log(ret + 1)) is hard to code. Yes, but according to the documentation (http://support.sas.com/documentation/cdl/en/lrdict/64316/HTML/default/viewer.htm#a003121132.htm), "when x is close to 0, LOG1PX(x) can be more accurate than LOG(1+x)."
(I assume the 1PX stands for "1 plus x".)
Big deal, right? I mean it's not as if the other way (log(ret + 1)) is hard to code. Yes, but according to the documentation (http://support.sas.com/documentation/cdl/en/lrdict/64316/HTML/default/viewer.htm#a003121132.htm), "when x is close to 0, LOG1PX(x) can be more accurate than LOG(1+x)."
(I assume the 1PX stands for "1 plus x".)
Tuesday, January 15, 2013
Ext.js - Load data synchronously
Ext.js loading process is asynchronous: it will not wait for the data to be loaded. Rather, it will continue processing immediately. So you cannot expect the data you load to be immediately available. The following will make the load synchronous.
Before
launch: function()
{
// other stuff too...
loadComboBoxStores();
// other stuff too...
}
After
launch: function()
{
// other stuff too...
Ext.onReady(function()
{
loadComboBoxStores();
});
// other stuff too...
}
(I post this reluctantly as I have limited understanding of this. But my solution appears to work.)
post script: That didn't work. But this did...
According to the Ext.js 4 documentation, "Ajax server requests are asynchronous and this call (to get data from server) will return before the response (data) has been received. Process any returned data in a callback function."
So use of callback is the key. Callback is an optional parameter of the store.load().
Here is my first (and apparently successful) attempt at a callback function. Well, actually two callback functions. First, it dynamically loads a list of stores of combo boxes. Then it dynamically loads the contents of each of those stores of combo boxes.
There may be better ways of doing this, but it does work...
// Build stores for combox boxes
function loadComboBoxStores()
{
// Ajax server requests are asynchronous, meaning the call to Ajax will return immediately,
// before the response from the server has been received. Returned data should be processed
// in a callback function. (There are all sorts of references to this issue on the web.)
// create Model which can be used for all combo boxes
Ext.define('MyComboBoxModel', {
extend: 'Ext.data.Model',
fields: [
{name: 'value' , type: 'string'},
{name: 'display', type: 'string'}
]
});
var storeOfComboBoxStoreNames = Ext.getStore('ComboBoxStoreNames');
storeOfComboBoxStoreNames.load({
callback: function()
{
for (var i = 0; i < storeOfComboBoxStoreNames.getCount(); i++)
{
var row = storeOfComboBoxStoreNames.getAt(i);
// console.log("store: " + row.data.store);
Ext.create('Ext.data.Store',
{
storeId: row.data.store,
model : 'MyComboBoxModel'
} );
}
var storeOfComboBoxes = Ext.getStore('ComboBoxes');
storeOfComboBoxes.load({
callback: function()
{
for (var i = 0; i < storeOfComboBoxes.getCount(); i++)
{
var row = storeOfComboBoxes.getAt(i);
var store = Ext.getStore(row.data.store);
var model = store.model;
var record = new model( { value: row.data.value, display: row.data.display } );
store.add(record);
}
} // end inner callback
}); // end inner load
} // end outer callback
}); // end outer load
}
Before
launch: function()
{
// other stuff too...
loadComboBoxStores();
// other stuff too...
}
After
launch: function()
{
// other stuff too...
Ext.onReady(function()
{
loadComboBoxStores();
});
// other stuff too...
}
(I post this reluctantly as I have limited understanding of this. But my solution appears to work.)
post script: That didn't work. But this did...
According to the Ext.js 4 documentation, "Ajax server requests are asynchronous and this call (to get data from server) will return before the response (data) has been received. Process any returned data in a callback function."
So use of callback is the key. Callback is an optional parameter of the store.load().
Here is my first (and apparently successful) attempt at a callback function. Well, actually two callback functions. First, it dynamically loads a list of stores of combo boxes. Then it dynamically loads the contents of each of those stores of combo boxes.
There may be better ways of doing this, but it does work...
// Build stores for combox boxes
function loadComboBoxStores()
{
// Ajax server requests are asynchronous, meaning the call to Ajax will return immediately,
// before the response from the server has been received. Returned data should be processed
// in a callback function. (There are all sorts of references to this issue on the web.)
// create Model which can be used for all combo boxes
Ext.define('MyComboBoxModel', {
extend: 'Ext.data.Model',
fields: [
{name: 'value' , type: 'string'},
{name: 'display', type: 'string'}
]
});
var storeOfComboBoxStoreNames = Ext.getStore('ComboBoxStoreNames');
storeOfComboBoxStoreNames.load({
callback: function()
{
for (var i = 0; i < storeOfComboBoxStoreNames.getCount(); i++)
{
var row = storeOfComboBoxStoreNames.getAt(i);
// console.log("store: " + row.data.store);
Ext.create('Ext.data.Store',
{
storeId: row.data.store,
model : 'MyComboBoxModel'
} );
}
var storeOfComboBoxes = Ext.getStore('ComboBoxes');
storeOfComboBoxes.load({
callback: function()
{
for (var i = 0; i < storeOfComboBoxes.getCount(); i++)
{
var row = storeOfComboBoxes.getAt(i);
var store = Ext.getStore(row.data.store);
var model = store.model;
var record = new model( { value: row.data.value, display: row.data.display } );
store.add(record);
}
} // end inner callback
}); // end inner load
} // end outer callback
}); // end outer load
}
Saturday, January 12, 2013
SAS: Reading and Writing XML
SAS' xmlv2 libname engine makes it easy to read and write XML files!
Here's my source code:
* Create test SAS dataset ;
data work.kids;
input name $ age gender $;
datalines;
Kamina 6 F
Raelani 4 F
Elliott 1 M
;
run;
libname myxml xmlv2 "C:\temp\kids.xml";
* Write SAS data to XML ;
data myxml.kids;
set work.kids;
run;
* Read XML data into SAS;
data work.getback;
set myxml.kids;
run;
* Show what you got;
proc print data=work.getback;
run;
Here's the output from PROC PRINT:
Here's the XML that was written, and then read back in:
<?xml version="1.0" encoding="windows-1252" ?>
<TABLE>
<KIDS>
<name>Kamina</name>
<age>6</age>
<gender>F</gender>
</KIDS>
<KIDS>
<name>Raelani</name>
<age>4</age>
<gender>F</gender>
</KIDS>
<KIDS>
<name>Elliott</name>
<age>1</age>
<gender>M</gender>
</KIDS>
</TABLE>
Here's my source code:
* Create test SAS dataset ;
data work.kids;
input name $ age gender $;
datalines;
Kamina 6 F
Raelani 4 F
Elliott 1 M
;
run;
libname myxml xmlv2 "C:\temp\kids.xml";
* Write SAS data to XML ;
data myxml.kids;
set work.kids;
run;
* Read XML data into SAS;
data work.getback;
set myxml.kids;
run;
* Show what you got;
proc print data=work.getback;
run;
Here's the output from PROC PRINT:
| Obs | name | age | gender |
|---|---|---|---|
| 1 | Kamina | 6 | F |
| 2 | Raelani | 4 | F |
| 3 | Elliott | 1 | M |
Here's the XML that was written, and then read back in:
<?xml version="1.0" encoding="windows-1252" ?>
<TABLE>
<KIDS>
<name>Kamina</name>
<age>6</age>
<gender>F</gender>
</KIDS>
<KIDS>
<name>Raelani</name>
<age>4</age>
<gender>F</gender>
</KIDS>
<KIDS>
<name>Elliott</name>
<age>1</age>
<gender>M</gender>
</KIDS>
</TABLE>
Subscribe to:
Posts (Atom)
