Determining the value of a variable
You can use a <signal>
element to print out the value of a variable
at a specified point in your query.
Objective
The query you are writing keeps giving you an error at the same point each time you run it. You suspect the problem is that one if the variables is not receiving the expected value at that point in the query, and you need to find what value the variable is actually holding.
In this example a <foreach>
loop performs multiple tabulations using two
different variables. Upon executing the query, you receive the error Unequal
length iterators in <foreach>. You aren't sure how long the iterators
are or how to make them the same length.
Solution
Here is the original code that is producing the error:
<block name="computation" colname="xsales,qty,cost" seg="transid"> <base table="pub.doc.retail.altseg.sales_detail_transid"/> <loop with_="columns"> <outer> <base table="pub.doc.retail.altseg.sales_detail_transid"/> <columns/> <colord cols="label"/> <set collist="{str_to_lst(@colname;',')}"/> <set collist="'{lst_to_str(@collist;'\' \'')}'"/> <sel value="name={@collist}"/> </outer> <inner> <letseq names="{@columns}" keys="{pkg_names(@names)}"> <foreach var="{@colname}" col_label="{@keys}" tally_="@i"> <willbe name="sum_of_{@var}" label="Sum of {@columns.{@col_label}}" value="g_sum({@seg};;{@var})"/> </foreach> </letseq> </inner> </loop> <sel value="g_first1({@seg};;)"/> </block>
First, you figure out what how many iterators are held in the variable
colname
.
... <inner> <signal msg="{@colname}"/> <letseq names="{@columns}" keys="{pkg_names(@names)}"> ...
Then, in a separate query, run the code in the outer to find out how many iterators are in
the package columns
.
<block name="computation" colname="xsales,qty,cost" seg="transid"> <base table="pub.doc.retail.altseg.sales_detail_transid"/> <columns/> <colord cols="label"/> <set collist="{str_to_lst(@colname;',')}"/> <set collist="'{lst_to_str(@collist;'\' \'')}'"/> <sel value="name={@collist}"/> </block>
And the final code with improvements is:
<block name="computation" colname="xsales,qty,cost" seg="transid"> <base table="pub.doc.retail.altseg.sales_detail_transid"/> <loop with_="columns"> <outer> <base table="pub.doc.retail.altseg.sales_detail_transid"/> <columns/> <colord cols="label"/> <set collist="{str_to_lst(@colname;',')}"/> <set collist="'{lst_to_str(@collist;'\' \'')}'"/> <sel value="name={@collist}"/> <transpose/> </outer> <inner> <letseq names="{@columns}" keys="{pkg_names(@names)}"> <foreach var="{@colname}" col_label="{@keys}" tally_="@i"> <willbe name="sum_of_{@var}" label="Sum of {@columns.{@col_label}}" value="g_sum({@seg};;{@var})"/> </foreach> </letseq> </inner> </loop> <sel value="g_first1({@seg};;)"/> </block>
Discussion
To fix an error that has to do with the value(s) being held in a variable(s), it is helpful to
use a <signal>
message. Setting the message equal to the variable in
question will return the value of that variable at the point in the code where the signal is
placed. You know from the error message received that the problem lies with the values of
the iterators in the <foreach>
operation, colname
and
columns
. From setting colname
equal to the message, you
will discover that there are three elements and therefore three iterators within the
variable.
However, you can't use the same method to discover the values held in columns
because a signal message cannot display the value of a package. Instead, copy the code from
the outer loop which is used to create the package and run it in a separate query. You also
need to include the block so that you have the values of the variables used in this section
of the code. After executing this code, you obtain the table that generates the package.
The outer loop creates a package where each column name in the table is paired with the last item
in the column. Therefore, this table generates a one item package. In order to create a
three item package including each element in the table, you need to
<transpose>
this table.
Now columns
is a package that contains three pairs of values and when used with
<letseq>
in a <foreach>
loop, creates three
iterations.
Further reading
If you would like to learn more about the functions and operations discussed in this recipe, click on the links below: