I'm trying to turn my hash object into a macro so that I can do a match on a number of different analysis variables. Here is the part of the macro with the hash object. I feel that my issue must be with how I am calling/quoting the macros in the hash, because a different version of this hash works without the macro. Thoughts?
The errors I am getting are ERROR: DATA STEP Component Object failure. Aborted during the COMPILATION phase. ERROR 557-185: Variable data is not an object. And then later in the object, ERROR: File DATA.TEST_BANK_ACCOUNT_ALL_REGS.DATA does not exist.
data data.test_&match_field._all_regs;
if _N_ = 1 then do;
if 0 then set = data.test_&match_field._match_srt;
declare hash contractors(dataset:"data.test_&match_field._match_srt", multidata: 'yes');
contractors.defineKey("&match_var.");
contractors.defineData('fpds_duns',
'xxx_dod_contractor',
"&match_flag.",
'xxx_small_contractor',
'xxx_medium_contractor',
'xxx_large_contractor',
'xxx_reported_relationship',
'xxx_joint_venture_flag');
contractors.defineDone();
end;
set data.test_xxx_200;
rc = contractors.find(key:"&match_var.");
do while (rc=0);
if xxxx_duns = xxx_hq_parent_duns_number or
xxxx_duns = xxx_hq_parent_duns_number or
xxxx_duns = xxx_global_parent_duns_number then xxx_reported_relationship = 'Y';
else xxx_reported_relationship = 'N';
output data.test_&match_field._all_regs;
rc = contractors.find_next(key:"&match_var.");
end;
run;
Related
I am having an issue with my code where it is working when I am hard coding the value (in comments) in the IF statement but when I insert the macro variable, the functions 'Copy' and 'Delete' do not work with no errors generated. Below is the code being used:
*%let pathscr = //files/FEB_P000/Reporting_FS;
%let pathdes = //files/FEB_P000/Reporting_FS/Accounting log/2021;
%let fn = LFNPAccounting;
%let dt = %sysfunc(inputn(&acc_date, yymmddn8.),yymmddn8.); /* 20211209 */
%let Var = &fn&dt;/* LFNPAccounting20211209 */
data _null_;
length fref $8 fname $256;
did = filename(fref,'\\files\FEB_P000\Reporting_FS');
did = dopen(fref);
do i = 1 to dnum(did);
fname = dread(did,i);
newfn = SUBSTR(fname,1,22);
if newfn = &Var then do;
/*if newfn = 'LFNPAccounting20211209' then do;*/
rc1=filename('src',catx('/',"&pathscr",fname));
rc2=filename('des',catx('/',"&pathdes",fname));
rc3=fcopy('src','des');
rc4= fdelete('src');
end;
end;
run;*
Could anyone help please?
Thanks
Hans
I am guessing you try to look into a specified folder pathscr, and if a file matches a certain string (SUBSTR(fname,1,22)), you copy and delete the latter to the Logs folder pathdes.
libname report "/home/kermit/temp/Reporting/";
data report.have20211210
report.have20211209
report.have20211208;
id = 1;
output;
run;
%let pathscr = /home/kermit/temp/Reporting/;
%let pathdes = /home/kermit/temp/Logs/;
%let fn = have; /* Name of the file */
%let type = .sas7bdat; /* File extension */
%let dt = %sysfunc(inputn(%sysfunc(today()), yymmddn8.), yymmddn8.);
%let file = &fn&dt&type.;
%put &=file;
data _null_;
drop rc did;
rc=filename("mydir", "&pathscr.");
did=dopen("mydir");
if did > 0 then do; /* check that the directory can be opened */
do i=1 to dnum(did); /* use dnum() to determine the highest possible member number */
fname=dread(did, i); /* get the name of the file */
if fname = "&file." then do; /* if the name of the file match: */
rc=filename('src', "&pathscr&file.");
rc=filename('des', "&pathdes&file.");
rc=fcopy('src', 'des'); /* copy from source to destination */
rc=fdelete('src'); /* delete from source */
end;
end;
end;
else do; /* if directory cannot be open, put the error message to the logs */
msg=sysmsg();
put msg;
end;
run;
Logs:
FILE=have20211210.sas7bdat
DOPEN opens a directory and returns a directory identifier value (a number greater than 0) that is used to identify the open directory in other SAS external file access functions. If the directory cannot be opened, DOPEN returns 0, and you can obtain the error message by calling the SYSMSG function.
I used today() for the dt macro-variable for convenience sake, but you will have to change it to whatever date you are searching for.
Consider that with the code above, if the file is already in the Logs folder, it will not be overwritten. Note that you do not have to use the CATX function if you put another / at the very end of your specified path.
Result
Macro variables are not resolved when bounded by single quotes. They are resolved when within double quotes.
Try
did = filename(fref,"&path_scr");
You set VAR to a value like:
%let Var = LFNPAccounting20211209 ;
Then you use it to generate a SAS statement:
if newfn = &Var then do;
Which will resolve to
if newfn = LFNPAccounting20211209 then do;
Since I did not see you creating any variable named LFNPAccounting20211209 it is most likely that you want to use this statement instead:
if newfn = "&Var" then do;
So that the SAS code you generate will compare the value of NEWFN to a string literal instead of another variable.
Note: Since it looks like you are using WINDOWS filesystem you should make the comparison case insenstive.
if upcase(newfn) = %upcase("&Var") then do;
Given a given MySQL table
DESC tabl_foo;
--------------------------------
Field Type Null Key Default Extra
-----------------------------------------------------------------
fooId varchar(15) NO PRI NULL
FooDate date YES MUL NULL
I need to update FooDate for a given row. So I tried this code :
query->SQL->Add("UPDATE tbl_foo SET FooDate = :FooDate WHERE fooId = :id"):
// both arguments are AnsiString
query->Parameters->FindParam("id")->Value = FoodId;
query->Parameters->FindParam("FooDate")->Value = FooDate;
query->ExecSQL();
However, this fails
Incorrect date value: "" for folumn FooDate at row 1
It turns out that FooDate may be an empty string (or { data:NULL }), and MySQL does not like that. So, I tried setting Null() :
if (FooDate.IsEmpty())
query->Parameters->FindParam("FooDate")->Value = Null();
else
query->Parameters->FindParam("FooDate")->Value = FooDate;
But then I get this error :
Parameter object is improperly defined. Inconsistent or incomplete information was provided.
What should be the value to set for MySQL NULL?
To make the update the system needs to know the types of the parameters. It can deduce the type from the variant you apply, and MySQL can do certain conversions for you, but it's always best to specify the data type.
So what you would need is something like:
if((pParam=query->Parameters->FindParam("FooDate"))!=NULL)
{
pParam->DataType=ftDate;
if(FooDate.IsEmpty())
{
pParam->Value=Null();
}
else
{
pParam->Value=FooDate;
}
}
You may want to look at keeping FooDate as a TDateTime, but you will need to detect NULL dates properly.
Trying to update table by user specified values. But the values are not getting updated.
cout<<"\nEnter Ac No"<<endl;
cin>>ac;
cout<<"\nEnter Amount"<<endl;
cin>>amt;
/* Create merged SQL statement */
sql = "UPDATE RECORDS set BAL = '%d' where ACCOUNT_NO = '%d'",amt, ac;
/* Execute SQL statement */
rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
If I replace BAL and ACCOUNT_NO by some integer value instead of place holder then it is working fine.
Your sql string is not being created properly.
If you expect this code
sql = "UPDATE RECORDS set BAL = '%d' where ACCOUNT_NO = '%d'",amt, ac;
to result in
"UPDATE RECORDS set BAL = '1' where ACCOUNT_NO = '2'"
where
amt= 1 and ac = 2 then you need to use a string formatting call like this.
// the buffer where your sql statement will live
char sql[1024];
// write the SQL statment with values into the buffer
_snprintf(sql,sizeof(sql)-1, "UPDATE RECORDS set BAL = '%d' where ACCOUNT_NO = '%d'",amt, ac);
buff[sizeof(sql)-1]='\0';
On your particular platform _snprintf(...) might be snprintf(..) or another similarly named function. Also your compiler may warn about buffer manipulation security vulnerabilities. Choose the appropriate substitute for your needs
I am trying to run an SQL stored procedure through ADO in C++. The procedure is called (for argument's sake) testProcedure and expects two parameters: #param1 and #param2. Here is a trimmed version of the code in the execution method:
m_mCommandParameters[_T("param1")] = _T("foo");
m_mCommandParameters[_T("param2")] = _T("bar");
pCommand.CreateInstance(__uuidof(Command));
pCommand->ActiveConnection = link;
pCommand->CommandType = adCmdStoredProc;
pCommand->CommandText = _T("testProcedure");
pCommand->PutPrepared(true);
pCommand->NamedParameters = true;
// Set up the variant to store the parameter values
VARIANT vParamValue;
vParamValue.vt = VT_BSTR;
CString paramCount; // Stores the count for use as parameter name
// Iterate through set parameters and apply them to command
map<CString,CString>::iterator mItr;
for(mItr = m_mCommandParameters.begin(); mItr != m_mCommandParameters.end(); mItr++) {
paramCount = mItr->first;
vParamValue.bstrVal = _bstr_t(mItr->second);
// Append the parameter
if (mItr->second.IsEmpty()) {
_variant_t vtNULL;
vtNULL.vt = VT_NULL;
pCommand->Parameters->Append(
pCommand->CreateParameter(_bstr_t(L"#"+paramCount),adVarChar,adParamInput,10,vtNULL)
);
} else {
pCommand->Parameters->Append(
pCommand->CreateParameter(_bstr_t(L"#"+paramCount),adVarWChar,adParamInput,
//commandParameters[i].GetLength()+1,
sizeof(vParamValue),
_bstr_t(vParamValue))
);
}
}
_variant_t vRecordsAffected;
pRecordSet = pCommand->Execute(&vRecordsAffected,NULL,adCmdStoredProc);
My understanding is that this should essentially execute the following:
testProcedure #param1 = 'foo', #param2 = 'bar'
If I open SQL management studio and run the above it works fine. But when I try and run the C++ I get the error:
database error IDispatch error #3092 80040e14 query : testProcedure;
[Microsoft][ODBC SQL Server Driver]Syntax error or access violation.
I only have SQL express so don't have SQL profiler; I usually use Express Profiler but for some reason it doesn't display any trace on stored procedured. So I am not sure how to start debugging this.
Thanks!
I am working in a configuration that uses the IOM to connect to the metadata server - hence there are no automatic macro variables in my environment to determine the user id (we are using a pooled workspace server with a generic host account).
Is there a short piece of code which can be used to query the metadata server for the SAS user id?
The following is quite long winded, and could probably be shortened - but it does the job!
data _null_;
call symput('login_id',''); /* initialise to missing */
n = 1;
length loginUri person $ 512;
nobj = metadata_getnobj("omsobj:Login?*",n, loginUri);
if (nobj>0) then do;
length __uri __objName __porig personUri $256;
__porig = loginUri;
__uri = '';
__objName = '';
__n = 1;
__objectFound = 0;
personUri = "";
__numObjs = metadata_getnasn(__porig ,"AssociatedIdentity", 1, __uri);
do until(__n > __numObjs | __objectFound );
__rc = metadata_getattr(__uri, "PublicType", __objName);
if __objName="User" then do;
__rc=metadata_getattr(__uri, "Name", __objName);
__objectFound = 1;
personUri = __uri;
end;
else do;
__n = __n+1;
rc = metadata_getnasn(__porig, "AssociatedIdentity", __n, __uri);
end;
end;
if upcase("N")="Y" and not __objectFound then do;
put "*ERROR*: Object with PublicType=" "User" " not found for parent " loginUri " under AssociatedIdentity association";
stop;
end;
;
rc = metadata_getattr(personUri, "Name", person);
call symput("login_id", trim(person));
end;
run;
%put &login_id;