How to do a search with multiple non-obligatory Input fields? - abap

I would like to ask how to do a basic search filtering in a selection screen that has multiple input fields which aren't required.
I tried to do it by using multiple IF statements followed by WHERE clauses which solves my current problem but its not fully correct, if i work with only a few inputs (2 at the moment, 'ID' and 'Number'), the code isn't too long, but if its over 10 or so it feel wrong to do it this way
What i tried so far was approximately like this :
IF lv_id IS INITIAL and lv_nr IS INITIAL.
SELECT * from DBase INTO TABLE Local_Table.
ELSEIF lv_id IS NOT INITIAL AND lv_nr IS INITIAL.
SELECT * from DBase INTO TABLE Local_Table WHERE ID = lv_nr.
ELSEIF lv_id IS INITIAL AND lv_nr IS NOT INITIAL.
SELECT * from DBase INTO TABLE Local_Table WHERE Number = lv_nr.
ELSEIF lv_id IS NOT INITIAL AND lv_nr IS NOT INITIAL.
SELECT * from DBase INTO TABLE Local_Table WHERE ID = lv_id AND Number = lv_nr.
The expected result is for the search to get executed correctly by having no input or multiple non-obligatory inputs, without having to write a very long code in case the number of inputs is high.

you can use the IN Operator in your WHERE clause when you have multiple conditions.
First You need to define a Selection Table for every parameter and have to fill them or leave them empty.
types: begin of myselopt ,
sign type char1 ,
option type char2 ,
low type ... (depends on the type you want select)
high type ... ,
end of myselopt .
types : t_selopt type table of myselopt .
data: gt_selopt type t_selopt ,
gt_selopt_2 type t_selopt_2 . #needs to be defined first
if lv_id is not initial .
insert value #( sign = 'I' option = 'EQ' low = lv_id ) into table gt_selopt .
endif .
if lv_nr is not initial .
insert value #( sign = 'I' option = 'EQ' low = lv_nr ) into table gt_selopt_2 .
endif .
You have to do this for every Parameter you want to query. And your query would look like this
select * from dbaste into table local_table where id in gt_selopt
and number in gt_selopt_2 .

You can define your input fields as SELECT-OPTIONS (with optional NO INTERVALS NO-EXTENSION to mimick the look of PARAMETERS). Then just use the IN operator in your WHERE clause:
REPORT.
DATA: your_ztable TYPE your_ztable.
SELECT-OPTIONS: s_id FOR your_ztable-id NO INTERVALS NO-EXTENSION,
s_nr FOR your_ztable-number NO INTERVALS NO-EXTENSION.
AT SELECTION-SCREEN.
SELECT * FROM your_ztable
WHERE id IN #s_id
AND number IN #s_nr
INTO TABLE #DATA(local_table).

What about this approach with concatenated where conditions?
DATA:
lv_where TYPE string.
IF lv_id IS NOT INITIAL.
CONCATENATE ' AND ID' space '=' space '"' lv_id '"' INTO lv_where.
ENDIF.
IF lv_nr IS NOT INITIAL.
CONCATENATE ' AND Number' space '=' space '"' lv_nr '"' INTO lv_where.
ENDIF.
IF lv_where IS NOT INITIAL.
SHIFT lv_where By 5 PLACES. " to remove leading _AND_ (
ENDIF.
SELECT * from DBase INTO TABLE Local_Table WHERE (lv_where).

Related

In SQL Server, how can I search for column with 1 or 2 whitespace characters?

So I need to filter column which contains either one, two or three whitespace character.
CREATE TABLE a
(
[col] [char](3) NULL,
)
and some inserts like
INSERT INTO a VALUES (' ',' ', ' ')
How do I get only the row with one white space?
Simply writing
SELECT *
FROM a
WHERE column = ' '
returns all rows irrespective of one or more whitespace character.
Is there a way to escape the space? Or search for specific number of whitespaces in column? Regex?
Use like clause - eg where column like '%[ ]%'
the brackets are important, like clauses provide a very limited version of regex. If its not enough, you can add a regex function written in C# to the DB and use that to check each row, but it won't be indexed and thus will be very slow.
The other alternative, if you need speed, is to look into full text search indexes.
Here is one approach you can take:
DECLARE #data table ( txt varchar(50), val varchar(50) );
INSERT INTO #data VALUES ( 'One Space', ' ' ), ( 'Two Spaces', ' ' ), ( 'Three Spaces', ' ' );
;WITH cte AS (
SELECT
txt,
DATALENGTH ( val ) - ( DATALENGTH ( REPLACE ( val, ' ', '' ) ) ) AS CharCount
FROM #data
)
SELECT * FROM cte WHERE CharCount = 1;
RETURNS
+-----------+-----------+
| txt | CharCount |
+-----------+-----------+
| One Space | 1 |
+-----------+-----------+
You need to use DATALENGTH as LEN ignores trailing blank spaces, but this is a method I have used before.
NOTE:
This example assumes the use of a varchar column.
Trailing spaces are often ignored in string comparisons in SQL Server. They are treated as significant on the LHS of the LIKE though.
To search for values that are exactly one space you can use
select *
from a
where ' ' LIKE col AND col = ' '
/*The second predicate is required in case col contains % or _ and for index seek*/
Note with your example table all the values will be padded out to three characters with trailing spaces anyway though. You would need a variable length datatype (varchar/nvarchar) to avoid this.
The advantage this has over checking value + DATALENGTH is that it is agnostic to how many bytes per character the string is using (dependant on datatype and collation)
DB Fiddle
How to get only rows with one space?
SELECT *
FROM a
WHERE col LIKE SPACE(1) AND col NOT LIKE SPACE(2)
;
Though this will only work for variable length datatypes.
Thanks guys for answering.
So I converted the char(3) column to varchar(3).
This seemed to work for me. It seems sql server has ansi padding that puts three while space in char(3) column for any empty or single space input. So any search or len or replace will take the padded value.

Remove a special character that exists between 2 characters

I have the following string:
6103951001#136,00#S0#0#99999999#8000010000#10.12.2019#
31.10.2019#"MATZOURAKIS IOANNISMROA118#OSPh"#99470##APE A 54226#K
What I want is to delete the special character HORIZONTAL_TAB(#) which is between " here is the part of the string: "MATZOURAKIS IOANNISMROA118#OSPh"
How can I do?
Thanks
PS. I am using the following to upload the data from a TAB delimited text file
data: data_table type standard table of char255,
wa_data_table like line of data_table.
lv_file = p_file.
cl_gui_frontend_services=>gui_upload(
exporting
filename = lv_file
filetype = 'ASC'
changing
data_tab = data_table
Now I am doing the following in order to catch the problem
loop at data_table into wa_data_table.
find all occurrences of '"' in wa_data_table match count lv_count.
if sy-subrc = 0 and lv_count = 2.
* REPLACE ALL OCCURRENCES OF REGEX
* '(#(?=[^"]*"[^"]*(?:"[^"]*"[^"]*)*$))' IN wa_data_table WITH ' '.
split wa_data_table at '"'
into split_data1 split_data2 split_data3.
replace all occurrences of cl_abap_char_utilities=>horizontal_tab
in split_data2 with ' '.
concatenate split_data1 split_data2 split_data3
into wa_data_table.
endif.
endloop.
I think that we must handle the cl_abap_char_utilities=>horizontal_tab not with the character # but in another way.
You can use following in ABAP to find this character and replace it:
data : lv_test type string VALUE '6103951001#136,00#S0#0#99999999#8000010000#10.12.2019# 31.10.2019#"MATZOURAKIS IOANNISMROA118#OSPh"#99470##APE A 54226#K'.
REPLACE ALL OCCURRENCES OF REGEX '(#(?=[^"]*"[^"]*(?:"[^"]*"[^"]*)*$))' IN lv_test WITH ''.
write lv_test.
This is the correct solution for this problem.
replace all occurrences of regex
'(\t(?=[^"]*"[^"]*(?:"[^"]*"[^"]*)*$))'
in table data_table with ' '.
replace all occurrences of regex '["]' in table data_table with ''.

PDI: Is there is a way I can substitute comma separated strings in Table Input SQL where column in?

I'm trying to substitute a comma separated string in the WHERE COLUMN IN query inside table input in PDI. I have a string query = ("car", "bike") and I want to substitute in SELECT * FROM vehicles where item in ?.
I tried to pass this string to the ? in the Table Input using replace variables and taking it from the previous step (Set Variables) which generates the query variable. It doesn't work this way because PDI adds "" around my variable and this the IN query doesn't work.
SELECT
item_id
, GROUP_CONCAT(DISTINCT name ORDER BY item_id, name SEPARATOR '", "') AS car_names
FROM testData
GROUP BY item_id
LIMIT 1
;
Modified Java Script Value:
var str = '';
var newtax = str.concat('(', '"', car_names, '"', ')');
// next step is to Set Variable
select
distinct name as 'car_name'
from vehicle
where name in '${query}'
union all
select "test1" as 'car_name'
from dual
union all
select "test2" as 'car_name'
from dual
union all
select "test3" as 'car_name'
from dual
limit 3
;```
expected result is
car
bike
test1
actual result:
2019/08/27 14:30:16 - hh.0 - Caused by: org.pentaho.di.core.exception.KettleDatabaseException:
2019/08/27 14:30:16 - hh.0 - Error setting value #1 [String] on prepared statement
2019/08/27 14:30:16 - hh.0 - Parameter index out of range (1 > number of parameters, which is 0).
In cases such as this, I would have the list in the form 'car,bike' (like what you're getting from group_concat()) and then use find_in_set() instead ofwhere ... in (...)
select
distinct name as 'car_name'
from vehicle
where find_in_set(name, ?)

sql select statement with field having multiple values

I have few check-boxes on my selection screen. Each check-box corresponds to a value which a field of a table can take. I have to then fire a select query where a particular field of a table can have all values whose corresponding check-box is selected.
Suppose I have 5 check-box corresponding to values a1-a5.
Now if check-boxes 1, 3, and 4 are checked then the field of the table can have values a1 or a3 or a4.
select * from table where field = a1 or field = a2 or field = a3.
One way to do this is creating 5 variables and then doing something like this
if checkbox1 checked
then var1 = a1
else
var1 = '0' //something which would never occur in the field of the table
and so on for all check-boxes.
And then
select * from table where field = var1 or field = var2 or field = var3 or field = var4 or field = var5.
This becomes difficult if there are 15 check-boxes.
Is there a better way to do this?
Use a select-option/range table for this:
DATA field_range TYPE RANGE OF data_type_of_table_field.
IF p_check1 = abap_true.
field_range = VALUE #( BASE field_range ( sign = 'I' option = 'EQ' low = 'A1' ) ).
ENDIF.
IF p_check2 = abap_true.
field_range = VALUE #( BASE field_range ( sign = 'I' option = 'EQ' low = 'A2' ) ).
ENDIF.
" ...
SELECT whatever FROM wherever WHERE field IN field_range.
CAUTION: An empty range table will match anything ("no restrictions") and fetch the entire contents of the database table, so you'll usually need to check for this separately.
Try like this
select * from table where field IN (a1,a2,a3 ...)
one possible way: append checked values to an internal table and then use FOR ALL ENTRIES in select statement.

LOAD DATA INFILE (*.csv) - ignore empty cells

I'm about to import a large (500 MB) *.csv file to a MySQL database.
I'm as far as that:
LOAD DATA INFILE '<file>'
REPLACE
INTO TABLE <table-name>
FIELDS
TERMINATED BY ';'
OPTIONALLY ENCLOSED BY '"'
IGNORE 1 LINES ( #Header
<column-name1>,
<column-name2>,
...
);
I have a problem with one of the coluns (it's data type is int) - I get an error Message:
Error Code: 1366 Incorrect integer value: ' ' for column at row
I looked at this line in the *.csv-file. The cell that causes the error has just a whitespace inside (like this: ...; ;...).
How can I tell SQL to ignore whitespaces in this column?
As the *.csv-file is very big and I have to import even bigger ones afterwards, I'd like to avoid editing the *.csv-file; I'm looking for a SQL-solution.
Add a SET COLUMN like so:
LOAD DATA INFILE 'file.txt'
INTO TABLE t1
(column1, #var1)
SET column2 = #var1/100;
You need to replace the #var1/100 with an expression that handles the 'space' and convert to -Infinity or 0 or 42... not sure..
This answer was originally included in the question as an edit by #speendo; I have converted it into a proper answer.
The solution is:
LOAD DATA INFILE '<file>'
REPLACE
INTO TABLE <table-name>
FIELDS
TERMINATED BY ';'
OPTIONALLY ENCLOSED BY '"'
IGNORE 1 LINES ( #Header
<column-name1>,
<column-name2>,
#var1 #the variable that causes the problem
...
)
SET <column-name-of-problematic-column> = CASE
WHEN #var1 = ' ' THEN NULL
ELSE #var1
END
;