I'm trying to get this temp-table's name/variablename ('TT_Test') in code so I could compare it:
DEFINE TEMP-TABLE TT_Test NO-UNDO
FIELD Test AS CHAR
.
I've tried to use this without success:
PROCEDURE testProc:
DEF VAR name AS CHAR NO-UNDO.
name = TT_Test:NAME.
END PROCEDURE.
Is there any way to get it?
cName = TEMP-TABLE tt_test:NAME.
Related
When I create an object in a constructor,
myTable property is constructed on the fly, for example, from csv file. I want to have some validation for that property as I have for myInt.
Do you happen to know how to do that? In the future, I guess I will need a per-column validation...
classdef BigObject
properties
myInt (1,1) double {mustBeNonnegative, mustBeInteger} = 0;
myTable (?,?) table {mustBeGreaterThan(table{1}.Variables,1), mustBeLessThan(table{2} ? ,2)} = table;
I tried selecting columns
myTable table {mustBeGreaterThan(table{1},1)} = table;
myTable table {mustBeGreaterThan(table{2}.Variables,2)} = table;
myTable table {mustBeGreaterThan(table.Variables,3)} = table;
The best way to achieve this is to write your own simple property validation function. You can build this on top of existing functions. So, you might do something like this:
%% Base case - passes
t = table((1:10).', 'VariableNames',{'MyVar'});
someFcn(t);
%% Fails because value is negative
t2 = table(-(1:10).', 'VariableNames',{'MyVar'});
someFcn(t2)
% Example function that uses validation
function someFcn(t)
arguments
t {mustHavePositiveVar(t, 'MyVar')}
end
end
% Custom validation function
function mustHavePositiveVar(t, varName)
try
mustBeA(t, 'table');
mustBeMember({varName}, t.Properties.VariableNames)
mustBePositive(t.(varName));
catch E
error('Input must be a table with a variable named %s that is all positive', varName)
end
end
Note there's a nuance if you use the class constraint syntax at the same time as a property validation function - namely that the property gets assigned and type-coerced before the validation functions run. So if you're going to validate the type of an input, you need to omit the class constraint (otherwise the input might simply be coerced to the correct type anyway).
Hello Progress4GL Developers,
I am trying to consume a Magento SOAP API and am dealing with a dataset as my output.
Here is the example procedure from the WSDL Analayser:
I am expecting my XML response to look something like this:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:Magento">
<SOAP-ENV:Body>
<ns1:salesOrderListResponseParam>
<result>
<complexObjectArray>
<increment_id>600000018</increment_id>
<store_id>6</store_id>
</complexObjectArray>
<complextObjectArray>
<increment_id>600000019</increment_id>
<store_id>7</store_id>
</complexObjectArray>
</result>
</ns1:salesOrderListResponseParam>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The current code I have is the following where I am expecting an output in the resultTable temp-table (but nothing is currently being returned).
define variable hs as handle no-undo.
define variable hp as handle no-undo.
DEFINE VARIABLE cUsername AS CHARACTER INIT "USERNAME".
DEFINE VARIABLE cPassword AS CHARACTER INIT "PASSWORDAPIKEY".
DEFINE VARIABLE oSession AS CHARACTER NO-UNDO.
DEFINE VARIABLE iRequest AS LONGCHAR NO-UNDO.
DEFINE TEMP-TABLE complexObjectArray NO-UNDO
NAMESPACE-URI ""
FIELD key AS CHARACTER
FIELD value1 AS CHARACTER
XML-NODE-NAME "value"
FIELD filter_id AS RECID
XML-NODE-TYPE "HIDDEN".
CREATE complexObjectArray.
assign
complexObjectArray.key = "status"
complexObjectArray.value1 = "pending".
DEFINE DATASET filter NAMESPACE-URI ""
FOR complexObjectArray.
DEFINE TEMP-TABLE resultTable NO-UNDO
NAMESPACE-URI "complexObjectArray"
FIELD increment_id AS CHARACTER.
DEFINE DATASET resultData NAMESPACE-URI "salesOrderListResponseParam"
FOR resultTable.
create server hs.
hs:connect( "-WSDL WSDLADDRESSHERE" ).
run PortType set hp on server hs.
run login in hp ( input cUsername, input cPassword, output oSession ).
message oSession . PAUSE 100.
run salesOrderList in hp ( input oSession, input dataset filter, output dataset resultData ).
for each resultTable:
disp resultTable with 2 col.
end.
delete procedure hp.
hs:disconnect().
delete object hs.
There are no errors, but it fails to show a response in the temp-table.
Many Thanks in Advance!
First of all you should try to create a dataset that exactly matches your expected output. I would do it something like this.
I'm unsure about the namespace, ns1. You could try to include it in the XML-NODE-NAME or via the NAMESPACE-PREFIX attribute. But it might work even if you just leave it out.
DEFINE TEMP-TABLE ttResult NO-UNDO
XML-NODE-NAME "result"
FIELD id AS INTEGER SERIALIZE-HIDDEN.
DEFINE TEMP-TABLE ttcomplexObjectArray NO-UNDO
XML-NODE-NAME "complexObjectArray"
FIELD id as RECID SERIALIZE-HIDDEN
FIELD increment_id AS CHARACTER
FIELD store_id AS CHARACTER.
DEFINE DATASET dsSalesOrderListResponseParam XML-NODE-NAME "salesOrderListResponseParam"
FOR ttResult, ttcomplexObjectArray
PARENT-ID-RELATION pr1 FOR ttResult, ttcomplexObjectArray PARENT-ID-FIELD id.
DATASET dsSalesOrderListResponseParam:READ-XML("file", "c:\temp\xml.xml", ? , ? , ?).
This works with the "body" part of your expected response (XML-Envelope etc excluded) as below.
<?xml version="1.0" ?>
<salesOrderListResponseParam >
<result>
<complexObjectArray>
<increment_id>600000018</increment_id>
<store_id>6</store_id>
</complexObjectArray>
<complexObjectArray>
<increment_id>600000019</increment_id>
<store_id>7</store_id>
</complexObjectArray>
</result>
</salesOrderListResponseParam>
Start with saving your response as the dataset sees it:
dsSalesOrderListResponseParam:WRITE-XML("file", "response.xml").
Then you can look at the file and see what's there. That's a start at least!
Thanks #Jensd for your answer. Using the write-xml statement really helps to identify how the dataset is structured.
There were three problems with my code above.
It needed the SERIALIZE-NAME statement in the temp-tables.
The filter was not being created correctly, and by using the write-xml statement I was able to identify what was going wrong.
I needed to assign a filter_id to the complexobjectarray which is equal to the recid of the filter temptable (which basically nests the XML as needed).
Please find below the code which resolved this issue (should it be of use to anybody else trying to do this):
define variable hs as handle no-undo.
define variable hp as handle no-undo.
DEFINE VARIABLE cUsername AS CHARACTER INIT "USER".
DEFINE VARIABLE cPassword AS CHARACTER INIT "PASS".
DEFINE VARIABLE oSession AS CHARACTER NO-UNDO.
DEFINE VARIABLE iRequest AS LONGCHAR NO-UNDO.
/* creating the filter */
DEFINE TEMP-TABLE filter NO-UNDO
FIELD filter_field AS INTEGER
XML-NODE-TYPE "HIDDEN" .
DEFINE TEMP-TABLE complexObjectArray NO-UNDO
SERIALIZE-NAME "complexObjectArray"
FIELD key AS CHARACTER
FIELD value1 AS CHARACTER
XML-NODE-NAME "value"
FIELD filter_id AS RECID
XML-NODE-TYPE "HIDDEN" .
CREATE filter.
CREATE complexObjectArray.
assign
complexObjectArray.key = "status"
complexObjectArray.value1 = "pending"
complexObjectArray.filter_id = RECID(filter).
.
DEFINE DATASET filters
FOR filter, complexObjectArray
PARENT-ID-RELATION RELATION1 FOR filter, complexObjectArray
PARENT-ID-FIELD filter_id.
/* debug dataset filters */
DATASET filters:WRITE-XML("file", "/home/jbetts/request.xml", ? , ? , ?).
DEFINE TEMP-TABLE resultTable NO-UNDO
SERIALIZE-NAME "complexObjectArray"
FIELD increment_id AS CHARACTER.
DEFINE DATASET resultData SERIALIZE-NAME "salesOrderListResponseParam"
FOR resultTable.
create server hs.
hs:connect( "-WSDL WSDLHERE" ).
run PortType set hp on server hs.
run login in hp ( input cUsername, input cPassword, output oSession ).
message oSession . PAUSE 100.
run salesOrderList in hp ( input oSession, input dataset filters, output dataset resultData ).
for each resultTable:
disp resultTable.increment_id format "x(30)".
end.
find first resultTable no-lock no-error.
if not available resulttable then message "no results".
delete procedure hp.
hs:disconnect().
delete object hs.
Wanted to create the multiple parameter of function but it gives me this error:
CREATE FUNCTION failed because a column name is not specified for
column 1.
Code below:
create function dmt.Impacted(
#nameOfColumn varchar , #nameOfParam varchar)
returns table
as
return
(select
case when '['+#nameOfColumn+']' is null or len(rtrim('['+#nameOfColumn+']')) = 0
then Convert(nvarchar(2),0)
else
#nameOfParam end from employee) ;
As the error message clearly said, the column in the returned result need a name. Either give it an alias in the SELECT like
SELECT CASE
...
END a_column_name
...
or define it in the declaration of the return type as in
...
RETURNS TABLE
(a_column_name nvarchar(max)
...
As you can see in the second form you have to specify a data type. As your current code doesn't make much sense now I cannot figure out what is the right one there. You'd need to amend it.
Note, that len(rtrim('['+#nameOfColumn+']')) = 0 is never true as len(rtrim('['+#nameOfColumn+']')) is either NULL, when #nameOfColumn is NULL or at least 2 because of the added brackets.
If #nameOfColumn is supposed to be a column name you shouldn't use varchar (especially without a length specified for it) but sysname which is a special type for object names.
Either way you should define a length for #nameOfColumn and #nameOfParam as just varchar without any length means varchar(1), which is probably not what you want. And maybe instead of varchar you want nvarchar.
You may also want to look into quotename().
Define name of column in SELECT statement :
(select case when '['+#nameOfColumn+']' is null or
len(rtrim('['+#nameOfColumn+']')) = 0
then Convert(nvarchar(2),0)
else #nameOfParam
end as name_column -- define column name
from employee)
Also, your function parameter has no data length, by default it will accept only 1 character #nameOfColumn varchar , #nameOfParam varchar & rest will trim.
I get a database table name at run time(let us suppose from user). I need to query the table and return few fields(which I know). How to do this?
"FOR EACH" wont accept a variable name in it. So, I cant use it.
I have gone through dynamic queries, especially SET-BUFFERS() method. Even with this, I need to know the table name before.
I need something like:
DEF VAR tablename AS CHAR.
tablename = somename.
FOR EACH tablename WHERE ....:
...
...
END.
Can someone please point me to right direction?
You can do a dynamic query with a dynamic buffer. Simply replace the value of cTableName variable in this example:
/* Replace _file with whatever field you're after */
DEFINE VARIABLE cTableName AS CHARACTER NO-UNDO INIT "_file".
DEFINE VARIABLE hQuery AS HANDLE NO-UNDO.
DEFINE VARIABLE hBuffer AS HANDLE NO-UNDO.
CREATE BUFFER hBuffer FOR TABLE cTableName.
CREATE QUERY hQuery.
hQuery:SET-BUFFERS(hBuffer).
hQuery:QUERY-PREPARE("FOR EACH " + cTableName).
hQuery:QUERY-OPEN().
REPEAT:
hQuery:GET-NEXT().
IF hQuery:QUERY-OFF-END THEN LEAVE.
DISPLAY hBuffer:BUFFER-FIELD(1):BUFFER-VALUE.
/* If you know the name of the field you can do: */
/* DISPLAY hBuffer:BUFFER-FIELD("nameoffield"):BUFFER-VALUE. */
END.
/* Clean up */
hQuery:QUERY-CLOSE().
hBuffer:BUFFER-RELEASE().
DELETE OBJECT hBuffer.
DELETE OBJECT hQuery.
What is the best way to access table data from a SAP system?
I tried it with it RFC_READ_TABLE, but this RFC returns the data in concatenated form within a single column and has a size restriction for row data.
Is there a better way to access SAP data in generic form without creating custom RFCs into the system?
I am searching for a standard RFC solution, not a custom script.
If I understand your question right, you want to read a table, but at time of programming, you don't know which table.
With Select * from (tablename)you can read with a dynamic table name.
The target field can be defined dynamic with create data.
An example (untested, currently I have no access to an SAP-system):
DATA: lv_tablename TYPE string,
ev_filelength TYPE i.
lv_tablename = 'mara'. "e.g. a parameter
DATA dref TYPE REF TO data.
CREATE DATA dref TYPE TABLE OF (lv_tablename).
FIELD-SYMBOLS: <wa> TYPE ANY TABLE.
ASSIGN dref->* to <wa>.
SELECT * FROM (lv_tablename) INTO TABLE <wa>. "Attention for test, may be large result
"<wa> is like a variable with type table mara
TYPES: BEGIN OF t_bseg,
*include structure bseg.
bukrs LIKE bseg-bukrs,
belnr LIKE bseg-belnr,
gjahr LIKE bseg-gjahr,
buzei LIKE bseg-buzei,
mwskz LIKE bseg-mwskz, "Tax code
umsks LIKE bseg-umsks, "Special G/L transaction type
prctr LIKE bseg-prctr, "Profit Centre
hkont LIKE bseg-hkont, "G/L account
xauto LIKE bseg-xauto,
koart LIKE bseg-koart,
dmbtr LIKE bseg-dmbtr,
mwart LIKE bseg-mwart,
hwbas LIKE bseg-hwbas,
aufnr LIKE bseg-aufnr,
projk LIKE bseg-projk,
shkzg LIKE bseg-shkzg,
kokrs LIKE bseg-kokrs,
END OF t_bseg.
DATA: it_bseg TYPE STANDARD TABLE OF t_bseg INITIAL SIZE 0,
wa_bseg TYPE t_bseg.
DATA: it_ekko TYPE STANDARD TABLE OF ekko.
*Select all fields of a SAP database table into in itab
SELECT *
FROM ekko
INTO TABLE it_ekko.
Try this snippet of RFC_READ_TABLE to get data in structured form:
DATA: oref TYPE REF TO cx_root,
text TYPE string,
obj_data TYPE REF TO data.
lt_options TYPE TABLE OF rfc_db_opt,
ls_option TYPE rfc_db_opt,
lt_fields TYPE TABLE OF rfc_db_fld,
ls_field TYPE rfc_db_fld,
lt_entries TYPE STANDARD TABLE OF tab512.
FIELD-SYMBOLS: <fs_tab> TYPE STANDARD TABLE.
TRY.
ls_option-text = `some query`.
APPEND ls_option TO lt_options.
ls_field-fieldname = 'PARTNER'.
APPEND ls_field TO lt_fields.
ls_field-fieldname = 'TYPE'.
APPEND ls_field TO lt_fields.
ls_field-fieldname = 'BU_GROUP'.
APPEND ls_field TO lt_fields.
ls_field-fieldname = 'BU_SORT1'.
APPEND ls_field TO lt_fields.
ls_field-fieldname = 'TITLE'.
APPEND ls_field TO lt_fields.
CALL FUNCTION 'RFC_READ_TABLE' DESTINATION dest
EXPORTING
query_table = 'BUT000'
TABLES
options = lt_options
fields = lt_fields
data = lt_entries.
CATCH cx_root INTO oref.
text = oref->get_text( ).
MESSAGE text TYPE 'E'.
ENDTRY.
IF lt_entries IS NOT INITIAL.
CREATE DATA obj_data TYPE TABLE OF but000.
ASSIGN obj_data->* TO <fs_tab>.
CREATE DATA obj_data TYPE but000.
ASSIGN obj_data->* TO FIELD-SYMBOL(<fs_line>).
LOOP AT lt_entries ASSIGNING FIELD-SYMBOL(<wa_data>).
LOOP AT lt_fields ASSIGNING FIELD-SYMBOL(<fs_fld>).
ASSIGN COMPONENT <fs_fld>-fieldname OF STRUCTURE <fs_line> TO FIELD-SYMBOL(<lv_field>).
IF <lv_field> IS ASSIGNED AND sy-subrc IS INITIAL.
<lv_field> = <wa_data>-wa+<fs_fld>-offset(<fs_fld>-length).
ENDIF.
APPEND <fs_line> TO <fs_tab>.
ENDLOOP.
ENDLOOP.
ENDIF.
IF <fs_tab> IS NOT INITIAL.
"Bingo!
ENDIF.