{"id":5,"date":"2009-08-21T12:06:32","date_gmt":"2009-08-21T17:06:32","guid":{"rendered":"http:\/\/anvil-of-time.com\/2009\/08\/21\/code-filter-user-object-for-powerbuilder-apps\/"},"modified":"2021-03-06T20:09:13","modified_gmt":"2021-03-07T01:09:13","slug":"code-filter-user-object-for-powerbuilder-apps","status":"publish","type":"post","link":"https:\/\/anvil-of-time.com\/powerbuilder\/code-filter-user-object-for-powerbuilder-apps\/","title":{"rendered":"Code Filter User Object for Powerbuilder Apps"},"content":{"rendered":"\n<p>When working with the end users who would be using the Purchasing System I was tasked with developing, a requirement came out very early in the process which might otherwise have caused concern; they wanted to sift their data based on any number of various codes assigned to it.\u00a0 Initially there were six different code types they wanted to use, in time this increased to ten.\u00a0 I wanted to implement as generic a solution as possible since there were four windows (initially) this type of behavior was going to apply to.<\/p>\n\n\n\n<p>The various code values themselves were pretty typical, (part class, material type, product group, etc.) but their numbers varied greatly from six to over twenty thousand.&nbsp; I wanted to offer the users the ability to enter both individual code values and code ranges at the same time to maximize flexibility.&nbsp; Due to the nature of the data involved, I used these objects to insert data into a series of tables which were subsequently referenced by a stored procedure which selected the desired records.&nbsp; However, the process can easily be used to manipulate a specific datawindow sql statement or to apply a filter to the results within a datawindow.<\/p>\n\n\n\n<p>The code is PFC based and makes use of the error service.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted VB\">Datawindow Object d_code_filter (external data source)\ntable(column=(type=char(50) updatewhereclause=no name=codeline dbname=&quot;codeline&quot; )\ncolumn=(type=char(30) updatewhereclause=no name=tablename dbname=&quot;tablename&quot; )\ncolumn=(type=char(1) updatewhereclause=no name=singledelim dbname=&quot;singledelim&quot; initial=&quot;;&quot; )\ncolumn=(type=char(1) updatewhereclause=no name=rangedelim dbname=&quot;rangedelim&quot; initial=&quot;-&quot; )\n)<\/pre>\n\n\n\n<p>Only the &#8216;codeline&#8217; column is visible on the datawindow object.<br><strong>&nbsp;n_cst_filterstring User Object (PFC Based),<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted VB\">global type n_cst_filterstring from n_srv\n\/\/Instance variables\nn_cst_string&amp;nbsp;&amp;nbsp;&amp;nbsp; inv_string \/\/ string checking service\n\nforward prototypes\npublic function long of_parsefilter (string as_filterstring, string as_delimiter, ref string as_filter[])\npublic function string of_buildfilter (string as_params, string as_delim, string as_replacestring)\npublic function integer of_checkrange (string as_source, string as_rangedelim, string as_singledelim)\nend prototypes\n\npublic function long of_parsefilter (string as_filterstring, string as_delimiter, ref string as_filter[]);\nlong&amp;nbsp;&amp;nbsp;&amp;nbsp; ll_return\n\/\/ parse the filter string into an array and return the array size\nlong&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; ll_arraylength\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_filterarray[]\nlong      ll_return = 1\n<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted VB\">\/\/ turn as_filtersting into an array\nll_arraylength = inv_string.of_parsetoarray(as_filterstring,as_delimiter,ls_filterarray)\nIF IsNull(ll_arraylength) THEN\n   ll_return = 0\nELSE\n   as_filter = ls_filterarray\n   ll_return = ll_arraylength\nEND IF\nRETURN ll_return\nend function<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted VB\">public function string of_buildfilter (string as_params, string as_delim, string as_replacestring);\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_return\nls_return = &#039;&#039;\nls_return = inv_string.of_globalreplace(as_params,as_delim,as_replacestring)RETURN ls_return\nend function<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted VB\">public function integer of_checkrange (string as_source, string as_rangedelim, string as_singledelim);\n\/\/ checks string &#039;as_source&#039;, which should be a\n\/\/ range of codes, to make sure that it is a\n\/\/ valid range designation and the first code\n\/\/ is of lesser or equal value to the second code.\n\/\/\n\/\/ example code range: 0100-0200\n\/\/ &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &#039;0100&#039; and &#039;0200&#039; are the codes\n\/\/ &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &#039;-&#039; is the range delimiter\n\/\/\n\/\/ returns -1 for error condition\n\/\/&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; 1 for success\n\/\/\ninteger &amp;nbsp;&amp;nbsp;&amp;nbsp; li_return\nlong&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; ll_singleoc\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_range[]\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_error[]\nli_return = 1\n\n\/\/how many &#039;elements&#039; are in the string\nll_singleoc = inv_string.of_countoccurrences(as_source,as_singledelim)\nIF (ll_singleoc = 0) THEN\n   inv_string.of_parsetoarray(as_source,as_rangedelim,ls_range)\n   IF (Upperbound(ls_range) &amp;lt;&amp;gt; 2) then\n      \/\/ ERROR CONDITION\n     \/\/ should have exactly two elements in a range\n      ls_error[1] = &#039;&#039;\n      gnv_app.inv_error.of_Message(&quot;1101&quot;, ls_error)\n      li_return = -1\n   ELSE\n      IF (Trim(Upper(ls_range[1])) &amp;gt; Trim(Upper(ls_range[2]))) THEN\n        \/\/ ERROR CONDITION\n        \/\/ element 1 cannot be greater than element 2\n        ls_error[1] = Trim(Upper(ls_range[1]))\n        ls_error[2] = Trim(Upper(ls_range[2]))\n        gnv_app.inv_error.of_Message(&quot;1101&quot;, ls_error)\n        li_return = -1\n      END IF\n   END IF\nEND IF\nRETURN li_return\nend function<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted VB\"> uo_code_filter object - User object\n\n\/\/This control is placed on the form.\nglobal type uo_code_filter from u_dw\ninteger width = 859\ninteger height = 104\nstring dataobject = &quot;d_code_filter&quot;\nboolean vscrollbar = false\nboolean ib_isupdateable = false\nstring is_updatesallowed = &quot;&quot;\nevent ue_mousemove pbm_mousemove\nend type\nglobal uo_code_filter uo_code_filter<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted VB\">type variables\nProtected:\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; is_filter[]\nend variables\n\nforward prototypes\npublic function integer of_settablename (string as_tablename)\npublic function integer of_setdefault (string as_default)\npublic function integer of_setdelim (string as_delimtype, string as_delim)\npublic function string of_gettablename ()\npublic function integer of_getfilter (ref string as_filter[])\npublic function string of_buildfilter (string as_columnname, string as_columntype)\npublic function string of_buildfilter (string as_columnname, string as_columntype, string as_prefixchar, long an_padamount)\nend prototypes<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted VB\">public function integer of_settablename (string as_tablename);\n\/\/ set the database table name the codes reside in\nint li_return\nli_return = 0\nIF IsNull(as_tablename) OR as_tablename = &#039;&#039; THEN\n&amp;nbsp;li_return = -1\nELSE\n&amp;nbsp;this.setitem(1,&#039;tablename&#039;,as_tablename)\nEND IF\nRETURN li_return\nend function<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted VB\">public function integer of_setdefault (string as_default);\n\/\/ sets the &#039;default&#039; value of the code which is\n\/\/ displayed when the window is opened or set to the defaults\nend function\n\npublic function integer of_setdelim (string as_delimtype, string as_delim);\n\/\/ external datawindow has default values of semi-colon(;) as single value delimiter\n\/\/ and dash(-) as the range delimiter.&amp;nbsp; Use this method if different delimiters\n\/\/ are desired.\n\/\/\n\/\/ sets the delimiters for the data entry\n\/\/ return -1 - bad delim type\n\/\/ return -2 - bad delim\n\/\/ return -3 - unknown delim type\n\/\/ return 0 - a okay\ninteger&amp;nbsp;&amp;nbsp;&amp;nbsp; li_return\nli_return = 0\nIF (IsNull(as_delimtype)) OR (as_delimtype = &#039;&#039;) THEN\n   li_return = -1\nEND IF\nIF (IsNull(as_delim)) OR (as_delim = &#039;&#039;) THEN\n   li_return = -2\nEND IF\nIF (li_return = 0) THEN\n   CHOOSE CASE upper(as_delimtype)\n      CASE &#039;SINGLE&#039;\n         this.setitem(1,&#039;singledelim&#039;,as_delim)\n      CASE &#039;RANGE&#039;\n         this.setitem(1,&#039;rangedelim&#039;,as_delim)\n      CASE ELSE\n         li_return = -3\n   END CHOOSE\nEND IF\nRETURN li_return\nend function<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted VB\">public function string of_gettablename ();\n\/\/ gets the database table name the codes reside in\nRETURN getitemstring(1,&#039;tablename&#039;)\nend function<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted VB\">public function integer of_getfilter (ref string as_filter[]);\n\/\/ sets the filter array\ninteger li_return\nli_return = 1\nas_filter = is_filter\nRETURN li_return\nend function\n\npublic function string of_buildfilter (string as_columnname, string as_columntype);\n\/\/ build the filter string (SQL syntax)\nlong&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; ll_i, ll_ac\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_rangedelim\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_range\nstring &amp;nbsp;&amp;nbsp;&amp;nbsp; ls_filterstring = &#039;&#039;\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_array[]\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_quote\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_replace\nn_cst_filterstring&amp;nbsp;&amp;nbsp;&amp;nbsp; lnv_filterstring\nlnv_filterstring = CREATE n_cst_filterstring\nCHOOSE CASE as_columntype\n   CASE &#039;S&#039; \/\/strings\n      ls_quote = &quot;&#039;&quot;\n   CASE ELSE \/\/ non strings\n      ls_quote = &#039;&#039;\nEND CHOOSE\nthis.event trigger pfc_accepttext(TRUE)\n\/\/ sets the is_filter array on the uo\nIF (this.event trigger pfc_validation() &amp;gt; 0) THEN\n&amp;nbsp;  this.of_getfilter(ls_array)\n&amp;nbsp;  ls_rangedelim = this.getitemstring(1,&#039;rangedelim&#039;)\n  ll_ac = Upperbound(ls_array)\n  FOR ll_i = 1 to ll_ac\n      IF (Upper(ls_array[ll_i]) = &#039;ALL&#039;) THEN\n         ls_range = &#039;&#039;\n         ls_filterstring = &#039;ALL&#039;\n         EXIT\n      END IF\n      IF (as_columnname = &#039;&#039;) THEN\n         ls_range = &#039;&#039;\n         ls_filterstring = ls_array[ll_i]\n         EXIT\n      END IF\n      IF (lnv_filterstring.inv_string.of_countoccurrences(ls_array[ll_i],ls_rangedelim) &amp;gt; 0) THEN\n         \/\/ found a range\n      &amp;nbsp;  IF (Len(ls_range) &amp;gt; 1) THEN \/\/ second range found\n            IF (Len(ls_filterstring) &amp;gt; 1) THEN\n              ls_filterstring = ls_filterstring + &quot; OR (&quot; + ls_range + &quot;)&quot;\n            ELSE\n              ls_filterstring =&amp;nbsp; ls_range\n            END IF\n              ls_range = &#039;&#039;\n         END IF\n            ls_replace = ls_quote +&quot; and &quot; + as_columnname + &quot; &amp;lt;= &quot;+ ls_quote\n            ls_range = lnv_filterstring.of_buildfilter(ls_array[ll_i],ls_rangedelim,ls_replace)\n            ls_range =&amp;nbsp; &quot; &quot; + as_columnname + &quot; &amp;gt;= &quot; + ls_quote + ls_range + ls_quote\n      ELSE\n         IF (Len(ls_filterstring) &amp;gt; 1) THEN\n            ls_filterstring = ls_filterstring + &quot; OR &quot; +as_columnname+&quot; = &quot;+ ls_quote + ls_array[ll_i] +ls_quote\n         ELSE\n            ls_filterstring = &quot; &quot;+as_columnname+&quot; = &quot; + ls_quote + ls_array[ll_i] + ls_quote\n         END IF\n      END IF\n   NEXT\n   IF (Len(ls_range) &amp;gt; 1) THEN\n      IF (Len(ls_filterstring) &amp;gt; 1) THEN\n         ls_filterstring = ls_filterstring + &quot; OR&amp;nbsp; (&quot; + ls_range + &quot;)&quot;\n      ELSE\n         ls_filterstring = ls_range\n         ls_range = &#039;&#039;\n      END IF\n   END IF\nEND IF\nDESTROY lnv_filterstring\nRETURN ls_filterstring\nend function<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted VB\">public function string of_buildfilter (string as_columnname, string as_columntype, string as_prefixchar, long an_padamount);\n\/\/ Polymorph to allow for prefix padding of values\nlong&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; ll_i, ll_ac\nlong&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; ll_p\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_rangedelim\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_range\nstring &amp;nbsp;&amp;nbsp;&amp;nbsp; ls_filterstring = &#039;&#039;\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_array[]\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_quote\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_replace\nn_cst_filterstring&amp;nbsp;&amp;nbsp;&amp;nbsp; lnv_filterstring\nlnv_filterstring = CREATE n_cst_filterstring\nCHOOSE CASE as_columntype\n   CASE &#039;S&#039; \/\/strings\n      ls_quote = &#039;&quot;&#039;\n   CASE ELSE \/\/ non strings\n      ls_quote = &#039;&#039;\nEND CHOOSE\nthis.event trigger pfc_accepttext(TRUE)\n\/\/ sets the is_filter array on the uo\nIF (this.event trigger pfc_validation() &amp;gt; 0) THEN\n   this.of_getfilter(ls_array)\n   ls_rangedelim = this.getitemstring(1,&#039;rangedelim&#039;)\n   ll_ac = Upperbound(ls_array)\n   FOR ll_i = 1 to ll_ac\n      IF (Upper(ls_array[ll_i]) = &#039;ALL&#039;) THEN\n         ls_range = &#039;&#039;\n         ls_filterstring = &#039;ALL&#039;\n         EXIT\n      ELSE \/\/ pad entry with prefix\n         FOR ll_p = 1 to an_padamount\n            ls_array[ll_i] = as_prefixchar + ls_array[ll_i]\n         NEXT\n      END IF\n      IF (as_columnname = &#039;&#039;) THEN\n         ls_range = &#039;&#039;\n         ls_filterstring = ls_array[ll_i]\n         EXIT\n      END IF\n      IF (lnv_filterstring.inv_string.of_countoccurrences(ls_array[ll_i],ls_rangedelim) &amp;gt; 0) THEN\n      \/\/ found a range\n         IF (Len(ls_range) &amp;gt; 1) THEN \/\/ second range found\n            IF (Len(ls_filterstring) &amp;gt; 1) THEN\n               ls_filterstring = ls_filterstring + &#039; OR (&#039; + ls_range + &#039;)&#039;\n            ELSE\n               ls_filterstring =&amp;nbsp; ls_range\n            END IF\n            ls_range = &#039;&#039;\n         END IF\n         ls_replace = ls_quote +&#039; and &#039; + as_columnname + &#039; &amp;lt;= &#039;+ ls_quote\n         FOR ll_p = 1 to an_padamount \/\/ pad end range item\n            ls_replace = ls_replace + as_prefixchar\n         NEXT\n         ls_range = lnv_filterstring.of_buildfilter(ls_array[ll_i],ls_rangedelim,ls_replace)\n         ls_range =&amp;nbsp; &#039; &#039; + as_columnname + &#039; &amp;gt;= &#039; + ls_quote + ls_range + ls_quote\n      ELSE\n         IF (Len(ls_filterstring) &amp;gt; 1) THEN\n            ls_filterstring = ls_filterstring + &#039; OR &#039; +as_columnname+&#039; = &#039;+ ls_quote + ls_array[ll_i] +ls_quote\n         ELSE\n            ls_filterstring = &#039; &#039;+as_columnname+&#039; = &#039; + ls_quote + ls_array[ll_i] + ls_quote\n         END IF\n      END IF\n   NEXT\n   IF (Len(ls_range) &amp;gt; 1) THEN\n      IF (Len(ls_filterstring) &amp;gt; 1) THEN\n         ls_filterstring = ls_filterstring + &#039; OR&amp;nbsp; (&#039; + ls_range + &#039;)&#039;\n      ELSE\n         ls_filterstring = ls_range\n         ls_range = &#039;&#039;\n      END IF\n   END IF\nEND IF\nDESTROY lnv_filterstring\nRETURN ls_filterstring\nend function\n\nevent constructor;call super::constructor;\n\/\/ basic stuff\nthis.of_setbase(TRUE)\nthis.insertrow(0) \/\/ needs a row\nthis.setrowfocusindicator(Off!)\nend event\n\nevent type integer pfc_validation();call super::pfc_validation;\n\/\/ validate the filter and parse it into an array\n\/\/ if a code range is involved it will be verified\n\/\/\n\/\/ example:&amp;nbsp; filterstring is &#039;0100-0200;0300;0400&#039;\n\/\/&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &#039;-&#039; is the range delimiter\n\/\/&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &#039;;&#039; is the single delimiter\n\/\/&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; resulting array is:\n\/\/&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; element[1] = &#039;0100-0200&#039; &amp;lt; a valid range\n\/\/&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; element[2] = &#039;0300&#039;\n\/\/&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; element[3] = &#039;0400&#039;\ninteger&amp;nbsp;&amp;nbsp;&amp;nbsp; li_return\ninteger&amp;nbsp;&amp;nbsp;&amp;nbsp; li_elements\ninteger&amp;nbsp;&amp;nbsp;&amp;nbsp; li_i\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_singledelim\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_rangedelim\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_filterstring\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_range[]\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_filter[]\nn_cst_filterstring&amp;nbsp;&amp;nbsp;&amp;nbsp; lnv_filterstring\nlnv_filterstring = CREATE n_cst_filterstring\nli_return = 1\nls_filterstring = this.getitemstring(1,&#039;codeline&#039;)\nls_singledelim = this.getitemstring(1,&#039;singledelim&#039;)\nls_rangedelim = this.getitemstring(1,&#039;rangedelim&#039;)\nli_elements = lnv_filterstring.of_parsefilter(ls_filterstring,ls_singledelim,ls_filter)\nIF (li_elements = 0) THEN\n   li_return = -1\n   \/\/invalid or no entry\n   \/\/ERROR CONDITION\nELSE\n   FOR li_i = 1 to li_elements\n   \/\/ is this element a range?\n      IF (lnv_filterstring.inv_string.of_countoccurrences(ls_filter[li_i],ls_rangedelim) &amp;gt; 0) THEN\n         \/\/ make sure range is in order\n         IF (lnv_filterstring.of_checkrange(ls_filter[li_i],ls_rangedelim,ls_singledelim) &amp;lt; 0) THEN\n           \/\/ERROR CONDITION\n           li_return = -1\n           EXIT\n        END IF\n      END IF\n   NEXT\nEND IF\nIF (li_return &amp;gt; 0) THEN\n   is_filter = ls_filter\nEND IF\nDESTROY lnv_filterstring\nRETURN li_return\nend event<\/pre>\n\n\n\n<p><strong>Code from windows with the object<\/strong><\/p>\n\n\n\n<p>User object placed on window is called &#8216;dw_category&#8217;<\/p>\n\n\n\n<pre class=\"wp-block-preformatted VB\">pfc_postopen event\ndw_category.of_setdefault(&#039;ALL&#039;)<\/pre>\n\n\n\n<p><em><strong>Sample code called from function &#8216;wf_getfilter&#8217; which returns ls_filterstring.<\/strong><\/em><\/p>\n\n\n\n<pre class=\"wp-block-preformatted VB\">string&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_filterstring\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_categories\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_replace\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_array[]\nstring&amp;nbsp;&amp;nbsp;&amp;nbsp; ls_sql\ninteger&amp;nbsp;&amp;nbsp;&amp;nbsp; li_rc\nn_cst_filterstring lnv_filterstring\nlnv_filterstring = CREATE n_cst_filterstring\nls_filterstring = &#039;&#039;\nls_categories = dw_category.of_buildfilter(&#039;categoryCode&#039;,&#039;S&#039;)\nCHOOSE CASE ls_categories\n   CASE &#039;ALL&#039;\n      \/\/ no real filter on the column\n      ls_categories = &#039;&#039;\n      ls_sql = &#039;insert into wrkInvActionListCategory values ( @@SPID, -1 )&#039;\n      EXECUTE IMMEDIATE :ls_sql;\n   CASE &#039;&#039;\n      \/\/ERROR\n   CASE ELSE\n      \/\/ got a filter so you can do something with it.\n      li_rc = wf_setwrktable(&#039;cprCategoryMaster&#039;,&#039;categoryKey&#039;, &#039; WHERE &#039;+ls_categories)\n      IF (li_rc &amp;lt; 0) THEN\n         \/\/ERROR CONDITION\n         Messagebox(this.title,&#039;Error setting Category filter.&#039;)\n      END IF\n   END CHOOSE\n\/\/ call the same methods on any other filter datawindows, capturing the filter string\n\/\/ into separate variables then combine them (or whatever)\/\/ category\nRETURN ls_categories<\/pre>\n\n\n\n<p><em><strong>Samples<\/strong><\/em><br>Data entered in field is: 0100-0120;0300;0500<br>Filter string returned is:<br>categoryCode = &#8216;0300&#8217; OR categoryCode = &#8216;0500&#8217; OR&nbsp; ( categoryCode &gt;= &#8216;0100&#8217; and categoryCode &lt;= &#8216;0120&#8217;)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When working with the end users who would be using the Purchasing System I was tasked with developing, a requirement came out very early in the process which might otherwise have caused concern; they wanted to sift their data based on any number of various codes assigned to it.\u00a0 Initially there were six different code&hellip;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[3],"tags":[12,16],"_links":{"self":[{"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/posts\/5"}],"collection":[{"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/comments?post=5"}],"version-history":[{"count":8,"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/posts\/5\/revisions"}],"predecessor-version":[{"id":1707,"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/posts\/5\/revisions\/1707"}],"wp:attachment":[{"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/media?parent=5"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/categories?post=5"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/anvil-of-time.com\/wp-json\/wp\/v2\/tags?post=5"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}