What is wrong with this SAS code? - proc-sql

I copy the code from a paper that i found on internet.
proc fcmp outlib=work.funcs.Test;
function whatAmI();
return(42);
endsub;
quit;
options cmplib=work.funcs;
data _null_;
rci = whatAmI();
put rci=; /* should be 42 */
run;
When I execute the code, it show the message:
ERROR 68-185: The function WHATAMI is unknown, or cannot be accessed.
I tried other functions and always show this message.
I change the libname, but nothing work.
What´s wrong?

I agree with Aditya.
Seems like 9.2 has the ability to actually use functions, while 9.1.3 only has the ability to more or less create them.
Check out THIS THREAD for more info.

Looks like a problem with the version. Make sure you are using SAS 9.2, since previous versions have a limited support of PROC FCMP.

Related

Can I stop the submitted statements on the first error?

Just for the debugging purpose: Is there a way to stop executing a series of submitted statements on the first error?
Let's say, I have three steps of code where the second statement has an error. Assume that I run all of them at once in the SAS window. Then, I expect SAS to successfully execute the first sentence and to stop working due to the error detected in the second sentence. Then I can easily go there to fix this.
But what's actually happening is that SAS tries to execute all three steps (i.e., 1st, 2nd (with error, though), and 3th). Hope that there is a solution for this.
Two remarks:
I found that the below code may help, but it didn't actually. Otherwise, please enlighten me.
options syntaxcheck dmssynchk;
I don't want to use the SAS option, errorabend because it shuts down SAS session itself. I just want my SAS stop "the submitted code" and want to fix the issue.
Thanks in advance.
There is a commonly used macro called %runquit that allows that... Not sure where it originates from, but here it goes:
%macro runquit;
; run; quit;
%if &syserr. ne 0 %then %do;
%abort cancel;
%end;
%mend runquit;
proc sort data=asdasd;
by _all_;
%runquit;
data abc;
a = 1;
b = 2;
c = 3;
%runquit;
The drawback is that you have to replace any run; or quit; statement with the call to %runquit, making the code less pretty.
A related StackOverflow question can be found here.
Also, see this discussion for other solutions.

parameters FDquery delphi does not work

i have the following delphi code:
FDQuery1.SQL.Clear;
FDQuery1.SQL.Add('SELECT * FROM :Tablename');
FDQuery1.ParamByName('Tablename').AsString := 'tasks';
ShowMessage(FDQuery1.sql.Text);
FDQuery1.Open;
(coppied from this link: http://www.delphigroups.info/2/da/237634.html)
it does not work because the parameter is not filled but stays the same.
does somebody know why it is not filled?
Because you cannot use parameters for table name substitution in SQL commands in general. You are lucky enough here though, FireDAC supports preprocessor macros to parametrize table names in SQL commands. So you can write for example this (note that if you want to see the command as you did in your code, it must be after macro preprocessing, that is e.g. after calling Prepare):
FDQuery1.SQL.Text := 'SELECT * FROM &TableName';
FDQuery1.MacroByName('TableName').AsIdentifier := 'tasks';
FDQuery1.Open;
For details about this kind of macros, see the substitution variables topic.

How to execute SQL Script which may or may not return data?

This is an extension of an old question of mine where the answer wasn't quite what I was asking. What I'm doing is executing SQL Script on an MS SQL Server database. This script may or may not return any recordsets. The problem is that the way that ADO components work, at least to my knowledge, I can only explicitly request one or the other.
If I know a query will return data, I use TADOQuery.Open
If I know a query will not return data, I use TADOConnection.Execute
If I don't know whether query will return data or not... ???
How can I execute any query and read the response to determine whether it has any recordsets or not so I can read that recordset?
What I've tried:
Calling TADOQuery.Open, but raises exception if there's no recordset
Calling TADOQuery.ExecSql, but never returns any data
Calling TADOConnection.Execute, but never returns any data
Using Option 3 and reverting to Option 1 on exceptions, but this is double the work (script files over 38,000 lines) and kinda nasty.
Using TADOCommand.Execute, but keeps raising "Parameter object is improperly defined. Inconsistent or incomplete information was provided" on creating some stored procedures (which otherwise don't happen when using TADOConnection.Execute).
Calling TADOConnection.Execute overload which returns _Recordset, but then the TADOConnection.Errors returns empty (and I depend on this).
Just as some background, the purpose is to implement something like the SQL Query tool in the SQL Server Management Studio. It allows you to execute any SQL script, and if it returns any recordsets, it displays them, otherwise it just displays output messages. The tool I'm working on automatically breaks SQL Script at GO statements, and executes each individual block separately. Some of those blocks might return data, and others might not. It's already obvious that I cannot make this determination prior to execution, so I'm looking for a way to go ahead with the execution and observe the result. TADOConnection.Execute provides some useful information, including the Errors (or output messages).
As of now, the only option I have is to supply an option in the user interface to allow the user to choose which type of execution to use - but this is what I'm trying to eliminate.
EDIT
The TADOCommand.Execute method is the closest to what I want. However, it fails on some bits of script which otherwise work perfectly fine using TADOConnection.Execute. See #5 above in "What I've tried". I almost wrote that as my answer, until I found this error happens on almost everything.
EDIT
After posting my answer below, I then came to learn that the Errors property no longer returns anything when I use this other overload of Execute. See #6 above in "What I've tried".
Calling...
ADOConnection1.Execute('select * from something', cmdText, []);
...does not return anything in ADOConnection1.Errors, whereas...
var
R: Integer;
begin
ADOConnection1.Execute('select * from something', R);
...does return messages in ADOConnection1.Errors, which is what I need, but yet, doesn't return any recordsets.
EDIT: Not the right solution
I discovered my solution finally after digging even deeper. The answer is to use the TADOConnection.Execute() overload which supports returning the recordset:
function TADOConnection.Execute(const CommandText: WideString;
const CommandType: TCommandType = cmdText;
const ExecuteOptions: TExecuteOptions = []): _Recordset;
Then, just assign the resulting _Recordset to the Recordset property of supported dataset components.
var
RS: _Recordset;
begin
RS := ADOConnection1.Execute('select * from something', cmdText, []);
if Assigned(RS) then begin
ADODataset1.Recordset:= RS;
...
end;
end;
The downside is that you cannot use the other overload which supports returning the RowsAffected. Also, nothing is returned in the Errors property of the TADOConnection when using this overload version of Execute, whereas the other one does. But that other doesn't return a recordset.

SQL Delphi "Parameter 'Subject' not found"

I have recently started to learn how to code in Delphi since moving from Python to do a project. I can't seem to find a fix to this issue. I have searched online for a couple of hours now and none of the 'fixes' seem to be working. I have tried using 'Query.ExecSQL', I have tried breaking the code up into segments, I have tried to assign edtSubject.Text to a variable and doing it that way, among a handful of other 'solutions' that haven't fixed the issue. I am really struggling with this and need a way to fix it that works quick, here is my code:
Query := TADOQuery.Create(Self);
Query.Connection := ADOConnection;
Query.SQL.Add('INSERT INTO tbl_RFI (Subject) VALUES (:Subject)');
Query.Parameters.ParamByName('Subject').Value := edtSubject.Text;
Query.ExecSQL;
I really hope that someone can help me with this,
Thanks.
Just add Query.ParamCheck := true before setting the SQl Text and it should be fine
Despite what others say I have had this same thing happen from time to time over the years in my production code.
Parameter 'ParameterName' not found
Always with ADO objects that were created in code. The best fix that I have found was here http://edn.embarcadero.com/article/20420
Basically just force the ADO object to reparse the parameters before you reference them.
EDIT: Thanks to Ken's feedback I have added a test first to check if the parameter exists before calling ParseSQL, thereby conserving the execution plan for the 99.9% of the time.
with TADODataSet.Create(nil) do
try
Connection := MyADOConnection;
CommandText := 'SELECT Foo ' +
'FROM FooBar ' +
'WHERE Bar = :Bar ';
if Parameters.FindParam('Bar') = nil then
Parameters.ParseSQL(CommandText, True); {<- THIS IS THE FIX }
Parameters.ParamByName('Bar').Value := 'value';
Open;
finally
Free;
end;
Since adding the ParseSQL I haven't had the problem.
Late reply I know, but I just went through the same situation, so in case this helps someone else. And it happens at random, "parameter not found" during in my case a tadocommand. Program errors out, restart doing exactly same sequence of events and works fine. Load up compiler, step through and works just fine. Set a breakpoint, and I can see the parameter not defined. But again, it's not every time, it's kind of random.
So it feels like some type of timing issue. I tried the ParseSQL command, and that actually makes it error out every time with a different error. I think the command text was getting cropped but did not investigate this. (it's a fairly long command)
Anyway, it seems I was able to fix this by adding in an application.processmessages after my tadocommand is created and sql text assigned.

How to quote values for LuaSQL?

LuaSQL, which seems to be the canonical library for most SQL database systems in Lua, doesn't seem to have any facilities for quoting/escaping values in queries. I'm writing an application that uses SQLite as a backend, and I'd love to use an interface like the one specified by Python's DB-API:
c.execute('select * from stocks where symbol=?', t)
but I'd even settle for something even dumber, like:
conn:execute("select * from stocks where symbol=" + luasql.sqlite.quote(t))
Are there any other Lua libraries that support quoting for SQLite? (LuaSQLite3 doesn't seem to.) Or am I missing something about LuaSQL? I'm worried about rolling my own solution (with regexes or something) and getting it wrong. Should I just write a wrapper for sqlite3_snprintf?
I haven't looked at LuaSQL in a while but last time I checked it didn't support it. I use Lua-Sqlite3.
require("sqlite3")
db = sqlite3.open_memory()
db:exec[[ CREATE TABLE tbl( first_name TEXT, last_name TEXT ); ]]
stmt = db:prepare[[ INSERT INTO tbl(first_name, last_name) VALUES(:first_name, :last_name) ]]
stmt:bind({first_name="hawkeye", last_name="pierce"}):exec()
stmt:bind({first_name="henry", last_name="blake"}):exec()
for r in db:rows("SELECT * FROM tbl") do
print(r.first_name,r.last_name)
end
LuaSQLite3 as well an any other low level binding to SQLite offers prepared statements with variable parameters; these use methods to bind values to the statement parameters. Since SQLite does not interpret the binding values, there is simply no possibility of an SQL injection. This is by far the safest (and best performing) approach.
uroc shows an example of using the bind methods with prepared statements.
By the way in Lua SQL there is an undocumented escape function for the sqlite3 driver in conn:escape where conn is a connection variable.
For example with the code
print ("con:escape works. test'test = "..con:escape("test'test"))
the result is:
con:escape works. test'test = test''test
I actually tried that to see what it'd do. Apparently there is also such a function for their postgres driver too. I found this by looking at the tests they had.
Hope this helps.