I have a table in Progress named Car . I need to have my progress code take an input parameter of one Car instance.
I've tried this
DEFINE INPUT PARAMETER i_tuPDO AS Car.
But this results in compiler error.
You cannot use a single record as input. You could either define an object that relates to the "car" record and input that object. Another option is to input the corresponding BUFFER-HANDLE instead.
DEFINE TEMP-TABLE tt NO-UNDO
FIELD a AS CHARACTER.
CREATE tt.
ASSIGN tt.a = "HELLO".
RUN proc (INPUT BUFFER tt:HANDLE).
PROCEDURE proc:
DEFINE INPUT PARAMETER phBuffer AS HANDLE NO-UNDO.
MESSAGE phBuffer:BUFFER-FIELD(1):BUFFER-VALUE VIEW-AS ALERT-BOX.
END.
If what you really want is inputting a DATASET into a procedure (or a program) that can be done like this:
DEFINE TEMP-TABLE tt NO-UNDO
FIELD a AS CHARACTER.
DEFINE DATASET ds FOR tt.
CREATE tt.
ASSIGN tt.a = "HELLO".
RELEASE tt.
RUN proc (INPUT DATASET ds).
PROCEDURE proc:
DEFINE INPUT PARAMETER DATASET FOR ds.
FIND FIRST tt NO-ERROR.
IF AVAILABLE tt THEN
DISPLAY tt.
END.
I'm not totally sure what you are trying to do. In case you want to pass a specific record of the table Car you could pass load the buffer and pass it or pass the rowid of the buffer. Example:
PROCEDURE test1 :
define parameter buffer pbCar for Car.
END procedure.
PROCEDURE test2 :
define input parameter rCar as rowid no-undo.
define buffer bCar for Car.
find bCar
where rowid(bCar) = rCar
no-lock.
END procedure.
find first Car no-lock.
run test1 ( buffer Car ).
run test2 ( rowid(Car) ).
Related
I'm using a window(.w) that has a button that passes a variable to a procedure(.p), does its magic and then needs to return the results in a temp-table back to the window for display.
The .w file
Definitions
DEFINE TEMP-TABLE Return_Results
FIELD tt_var1Return AS CHARACTER FORMAT "x(20)"
FIELD tt_var2Return AS CHARACTER FORMAT "x(30)"
FIELD tt_var3Return AS CHARACTER FORMAT "x(30)"
FIELD tt_var4Return AS CHARACTER FORMAT "x(30)"
.
Button code
ON CHOOSE OF RecordFinder IN FRAME Dialog-Frame
DO:
DEFINE VARIABLE varInput AS CHARACTER NO-UNDO
DEFINE VARIABLE Return_Results REFERENCE-ONLY. /* <--- I'm pretty sure this is the problem */
varInput = Fill-In:SCREEN-VALUE.
RUN RecordFinder.p(INPUT varInput, OUTPUT Return_Results).
FOR EACH Return_Results:
Display Return_Results.
END.
END.
The .p file
i'm omitting some stuff that i think may not be necessary, but it basically takes the input variable, matches it and generates a temp-table from the results and assign those records to a new temp-table that will get passed back.
Definitions
DEFINE INPUT PARAMETER windowInput AS CHARACTER NO-UNDO.
DEFINE OUTPUT PARAMETER Results_Output
DEFINE TEMP-TABLE Original_tt
FIELD tt_var1Original AS CHARACTER FORMAT "x(20)"
FIELD tt_var2Origianl AS CHARACTER FORMAT "x(30)"
FIELD tt_var3Original AS CHARACTER FORMAT "x(30)"
FIELD tt_var4Original AS CHARACTER FORMAT "x(30)"
.
DEFINE TEMP-TABLE Return_tt
FIELD tt_var1Return AS CHARACTER FORMAT "x(20)"
FIELD tt_var2Return AS CHARACTER FORMAT "x(30)"
FIELD tt_var3Return AS CHARACTER FORMAT "x(30)"
FIELD tt_var4Return AS CHARACTER FORMAT "x(30)"
.
*additional code that works*
The next bit of code is for sorting the result of the temp table where it matches the input variable
FOR EACH Original_tt WHERE Original_tt.Var1 = windowInput:
CREATE Return_tt.
BUFFER-COPY Original_tt TO Results_tt
Return_tt.tt_var1Return = Original_tt.tt_var1Original.
Return_tt.tt_var2Return = Original_tt.tt_var2Original.
Return_tt.tt_var3Return = Original_tt.tt_var3Original.
Return_tt.tt_var4Return = Original_tt.tt_var4Original.
/* This is where I know I'm wrong */
/* I figured you could assign the Return_tt to the output variable */
Results_Output = Return_tt.
END.
I hope this not too convoluted.
The doc at https://docs.progress.com/bundle/abl-reference/page/Parameter-passing-syntax.html has detail on the parameter passing syntax (though no decent example).
In the called program (.p) you need to define the parameters
DEFINE INPUT PARAMETER windowInput AS CHARACTER NO-UNDO.
DEFINE OUTPUT PARAMETER TABLE FOR Return_tt.
In the caller (.w), you say the following
RUN RecordFinder.p(INPUT varInput, OUTPUT TABLE Return_Results).
Now you have the data in your caller.
It's a deep copy (so the .W gets its very own copy in memory). This may cause you performance problems (since a copy must be made), although there are reasons for making deep copies too.
You can turn the deep (by value) call into a shallow (by reference) call quite easily.
RUN RecordFinder.p(INPUT varInput, OUTPUT TABLE Return_Results BY-REFERENCE).
Some further doc at https://docs.progress.com/bundle/develop-abl/page/Passing-a-temp-table-by-reference.html . You don't need to define the temp-table as REFERENCE-ONLY in the caller.
I have a table of records that has two logical flags, holdn and holdl. I want to loop through this table with 3 different criteria.
Either flag is TRUE - We want to see everything that is on hold
Flag holdl is TRUE - We only want see items that are on hold for this one reason
Flag holdn is TRUE - We only want to see items that are on hold for this other reason.
I cannot figure out how to dynamically change the for each loop based on this. What I have tried so far is to set the value of a variable based on these conditions and then use the content of the variable as one of the where parameters. This does not work as Progress complains that there is a data mismatch. The variable is a string, the flags are logical, so that does make sense. See sample code below. This is a snippet of the actual code with the the table name changed. The which-hold, order-from, etc variables are defined and set in a different module which calls this one.
DEFINE VARIABLE which-hold# AS CHARACTER FORMAT "x(30)" NO-UNDO.
CASE which-hold:
WHEN "B" THEN which-hold# = "(widget.holdn or widget.holdl)".
WHEN "L" THEN which-hold# = "widget.holdl".
WHEN "N" THEN which-hold# = "widget.holdn".
END CASE.
for each widget where which-hold# and
widget.order-no >= order-from and widget.order-no <= order-thru and
widget.line-no >= line-from and widget.line-no <= line-thru and
widget.joint-no >= joint-from and widget.joint-no <= joint-thru
no-lock:
A bunch of code to make a nice report with the retrieved records...
end.
Self taught Progress programmer here, who has inherited a huge, poorly documented application. Please be gentle.
If you would prefer not to deal with handles a semi-dynamic approach is also possible:
define variable i as integer no-undo.
define query q for customer.
do while true:
update i.
case i:
when 0 then quit.
when 1 then open query q for each customer no-lock where custNum >= 1000.
when 2 then open query q for each customer no-lock where state = "nh".
otherwise open query q for each customer no-lock where name begins "u".
end.
do while true with frame a:
get next q.
if not available customer then leave.
display custNum name state with frame a 10 down.
down with frame a.
end.
close query q.
end.
What you want is actually a dynamic query. I'll get to it at the end, but first I'd like to explain why you won't be able to try and substitute the field name in the which-hold# variable: because the query is evaluated at compile time. And this is what it reads (supposing which-hold# has a value of widget.holdn
FOR EACH widget where "widget-holdn" (...)
And that does not evaluate to TRUE or FALSE. So what, you ask? Well, that is the key here. Every condition needs to evaluate to true or false, so you'd be more in luck if you try
for each widget where (if widget-hold# = 'widget.holdn' then widget.holdn = true else TRUE) (...)
Again, notice the condition will exist if widget-hold# has the value I want, otherwise it doesn't filter on this at all.
So you can just code the way I showed (for each of the conditions you have) and it should work fine.
BUT let me suggest a dynamic query instead.
You need to have:
DEFINE VARIABLE hQuery AS HANDLE NO-UNDO.
CREATE QUERY hQuery.
hQuery:SET-BUFFERS(BUFFER widget:HANDLE).
hQuery:QUERY-PREPARE('<THIS IS THE CORE>').
hQuery:QUERY-OPEN().
DO WHILE hQuery:GET-NEXT():
A bunch of code to make a nice report with the retrieved records...
END.
So in the core you have a string that corresponds to your for each the way you want it to look. So it should be for example (store this in a variable, or assemble it inside the query prepare, it doesn't matter):
'FOR EACH widget NO-LOCK WHERE ' +
(if which-hold = 'B' then 'widget.holdn = true and widget.holdl = true'
else if which-hold = 'L' then 'widget-holdl = true'
else /* N */ 'widget-holdn = true').
Remember I said your query is evaluated at compile time? Well, just so you know, dynamic queries on the other end are evaluated at run time, so be prepared for errors to pop up only when you run. Another thing I should mention is dynamic queries are slower than static ones, so please evaluate and choose your poison :)
This should be what you need. Please let me know if it's helpful or any questions remain.
I am trying to write a simple PL/R function that finds the mean of a column (Greenplum 4.3.4 DB)
CREATE OR REPLACE FUNCTION mean_plr(val numeric[]) RETURNS numeric AS
$$
x <- val
avg = mean(x)
return(avg)
$$
LANGUAGE 'plr';
SELECT mean_plr(sensor1) FROM public.tempSensors;
This, however, gives me the error:
ERROR: function mean_plr(numeric) does not exist
LINE 1: SELECT mean_plr(sensor1) FROM public.tempSensors;
^
HINT: No function matches the given name and argument types. You may need to add explicit type casts.
Figured out what I was doing wrong. mean_plr(sensor1) sends 1 value at a time. To send entire column, we need to use array_agg() function.
SELECT mean_plr(array_agg(sensor1::numeric)) FROM public.tempSensors;
I would like to run a query involving joining a table to a manually generated list but am stuck trying to generate the manual list. There is an example of what I am attempting to do below:
SELECT
*
FROM
('29/12/2014', '30/12/2014', '30/12/2014') dates
;
Ideally I would want my output to look like:
29/12/2014
30/12/2014
31/12/2014
What's your Teradata release?
In TD14 there's STRTOK_SPLIT_TO_TABLE:
SELECT *
FROM TABLE (STRTOK_SPLIT_TO_TABLE(1 -- any dummy value
,'29/12/2014,30/12/2014,30/12/2014' -- any delimited string
,',' -- delimiter
)
RETURNS (outkey INTEGER
,tokennum INTEGER
,token VARCHAR(20) CHARACTER SET UNICODE) -- modify to match the actual size
) AS d
You can easily put this in a Derived Table and then join to it.
inkey (here the dummy value 1) is a numeric or string column, usually a key. Can be used for joining back to the original row.
outkey is the same as inkey.
tokennum is the ordinal position of the token in the input string.
token is the extracted substring.
Try this:
select '29/12/2014'
union
select '30/12/2014'
union
...
It should work in Teradata as well as in MySql.
I want to create a unix utility to insert 1 row into a sas dataset. When run, this scipt will ask user to insert value for each variable in the dataset(preferabely telling him the type and length of the variable). It will then pass these values to SAS using EXPORT command and then SAS will create macro variable for these variables and using 'proc sql; insert into' will insert the value into dataset.
data raw_str;
/* init PDV */
if 0 then
set tracking_data;
/* programmatic structure to enable addressing of vars */
array a_c(*) _character_;
array a_n(*) _numeric_;
run;
now raw_str will variables whose type and length be same as that of the tracking data
proc sql noprint;
select distinct name
into : varlist separated by ' '
from dictionary.columns
where libname='WORK'
and memname='raw_str';
quit;
then i want to pass this list to unix, from there i will ask user to enter value for these variables and then i will append these values into the tracking_data using.
problem is with passing values from unix to sas and creating macro variables for these values
I can also pass the length and type of variable to the front end, telling user to pass value which matched the type and length of raw_str dataset
proc sql;
insert into raw_str
values (&val1, &val2, &val3...);
quit;
finally i can use proc append to append it into the original data
Here's one possible approach for getting user-entered values from UNIX into SAS:
Have your UNIX shell script write out the user-entered values into a (consistently formatted) temporary text file, e.g. CSV
Write a SAS data step that can read the text file and import the values into the required formats. You can run proc import and look at the log to get an idea of the sort of code to use.
Have the script call SAS via the command line, telling it to run a program containing the data step you wrote.