Prettify a CodeEffect rule clause automatically - rule-engine

Is there a way to prettify the rule clause automatically?
For example, automatically format a rule from this:
Check if A is equal to B or ( B contains abc and C is not equal to A ) or ( C has no value and ( A starts with xyz or A doesn't end with opq ))
To this:
Check if
A is equal to B
or ( B contains abc
and C is not equal to A
)
or ( C has no value
and ( A starts with xyz
or A doesn't end with opq
)
)

You can't do rule formatting automatically in the current version. But rule authors can use the included keyboard and gestures support; it's quite intuitive and easy to use. Details can be found here

Related

Case ... when to create column based on other column values

I have two columns in a table. Variable - a,b,c,d, ..... and its respective Values - 1,2,3,4, .....
Now I create a third columns using case statements
Case
When Variable IN ( a,b ) Then 'Alpha'
When Variable IN ( c,d,e,f ) Then 'Beta'
When Variable IN (g,h,i) Then 'Gamma'
'As Attribute
This means, when I provide a Variable having its respective Value as above, I get the resultant Attribute.
Now, can I create another table where I input an Attribute and return the minimum or maximum value based on the Variable?
For Eg: If I input Beta, then the Minimum Value will be 3 (Value of Valiable 'c' since c,d,e,f have attribute Beta. In simple words reverse of the above example.
I am sure these is a simple way of doing this. Would love to see the creativity of experts here.
Case
When Variable IN ( a,b ) Then 'Alpha'
When Variable IN ( c,d,e,f ) Then 'Beta'
When Variable IN (g,h,i) Then 'Gamma'
'As Attribute
You'll need to do the min() calculation and then join back to the original table:
SELECT a.variable, b.attribute
FROM mytable a, (SELECT min(values) as v, attribute FROM mytable GROUP BY attribute) b
WHERE a.values = b.v;
variable | attribute
----------+-----------
a | Alpha
c | Beta
g | Gamma
(3 rows)

Query table by a value in the second dimension of a two dimensional array column

WHAT I HAVE
I have a table with the following definition:
CREATE TABLE "Highlights"
(
id uuid,
chunks numeric[][]
)
WHAT I NEED TO DO
I need to query the data in the table using the following predicate:
... WHERE id = 'some uuid' and chunks[????????][1] > 10 chunks[????????][3] < 20
What should I put instead of [????????] in order to scan all items in the first dimension of the array?
Notes
I'm not entirely sure that chunks[][1] even close to something I need.
All I need is to test a row, whether its chunks column contains a two dimensional array, that has in any of its tuples some specific values.
May be there's better alternative, but this might do - you just go over first dimension of each array and testing your condition:
select *
from highlights as h
where
exists (
select
from generate_series(1, array_length(h.chunks, 1)) as tt(i)
where
-- your condition goes here
h.chunks[tt.i][1] > 10 and h.chunks[tt.i][3] < 20
)
db<>fiddle demo
update as #arie-r pointed out, it'd be better to use generate_subscripts function:
select *
from highlights as h
where
exists (
select *
from generate_subscripts(h.chunks, 1) as tt(i)
where
h.chunks[tt.i][3] = 6
)
db<>fiddle demo

using patindex to replace characters

I have a table with a name column in it that contains names like:
A & A Turf
C & D Railways
D & B Railways
I have the following query that will get me the correct columns I want
select name from table where patindex('_ & _ %', name) > 0
What I need to accomplish is making anything with that type of pattern collapsed. Like this
A&A Turf
C&D Railways
D&B Railways
I'm also looking how I can do the same thing with single letter followed by a space followed by another single letter followed by a space then words with more then one letter like this
A F Consulting -> AF Consulting
D B Catering -> DB Consulting
but only if the single letter stuff is at the beginning of the value.
Example would be if the name has the pattern mentioned above anywhere in the name then don't do anything unless it's at the beginning
ALBERS, J K -> ALBERS, J K This would not change because it's a name and it's not at the beginning.
So something like this would be the desired result:
Original Name New Name Rule
____________ __________ ___________
A & K Consulting A&K Consulting Space Taken out between & for single characters
C B Finance CB Finance space taken out only if beginning beginning
Albert J K Albert J K not at beginning so left alone
This can be done without PATINDEX. Because what needs to be replaced is at the start, and has fixed patterns. So you already know the positions.
Example snippet:
DECLARE #Table TABLE (ID INT IDENTITY(1,1) PRIMARY KEY, name VARCHAR(30));
INSERT INTO #Table (name) VALUES
('A & K Consulting'),
('C B Finance'),
('Albert J K'),
('Foo B & A & R');
SELECT
name AS OldName,
(CASE
WHEN name LIKE '[A-Z] [A-Z] %' THEN STUFF(name,2,1,'')
WHEN name LIKE '[A-Z] & [A-Z] %' THEN STUFF(name,2,3,'&')
ELSE name
END) AS NewName
FROM #Table;
Test on rextester here
The first one is straightforward: replace " & " with "&". The second I'll have to take more time.

Drools: Default value for queries in case of no match

I'm writing a Drools rule set processing events of type A and B; and in many of the rules I need to compare A's attribute timestamp to maximum of a subset of B's attribute windowStart to qualify that A event. If that subset of B is an empty set, I assume there is no windowStart, and so the value 0 is desired. Any A's with the a timestamp greater than windowStart will qualify.
Consider the following pseudo code for elaboration:
long findMaxWindowStartOrZero(int bID)
{
Set bSubset = getAllBWithID(bID);
if(bSubset is empty) return 0;
return max(bSubset, B::windowStart);
}
without such query, LHS of every rule concerning this comparison needs to be duplicated, once to account for absence of any B and once to find the actual maximum when the subset is non-empty.
Having such query as the pseudo code above makes this task substantially easier, and removes the need to branch the LHS. Is it possible to do that? Is there any drawback or benefit for doing that instead of branching LHS of mentioned rules?
rule qualify_A
when
accumulate( B( id == "bID", $ws: windowStart ); $mws: max( $ws ) )
$a: A( timestamp > $mws )
then
...process $a...
end
I think that this rule does not fire if there are no matching Bs. To work around this, insert a B with windowStart set to 0. This dummy could also be used to define the value for matching B's id:
rule qualify_A
when
B( $id: id, windowStart == 0 ) // the dummy, defines id
accumulate( B( id == $id, $ws: windowStart ); $mws: max( $ws ) )
$a: A( timestamp > $mws )
then
...process $a...
end

Greatest N per group in Open SQL

Selecting the rows from a table by (partial) key with the maximum value in a particular column is a common task in SQL. This question has some excellent answers that cover a variety of approaches to it. Unfortunately I'm struggling to replicate this in my ABAP program.
None of the commonly used approaches seem to be supported:
Joining on a subquery is not supported in syntax: SELECT * FROM X as x INNER JOIN ( SELECT ... ) AS y
Using IN for a composite key is not supported in syntax as far as I know: SELECT * FROM X WHERE (key1, key2) IN ( SELECT key1 key2 FROM ... )
Left join to itself with smaller-than comparison is not supported, outer joins only support EQ comparisons: SELECT * FROM X AS x LEFT JOIN X as xmax ON x-key1 = xmax-key1 AND x-key2 < xmax-key2 WHERE xmax-key IS INITIAL
After trying each of these solutions in turn only to discover that ABAP doesn't seem to support them and being unable to find any equivalents I'm starting to think that I'll have no choice but to dump the data of the subquery to an itab.
What is the best practice for this common programming requirement in ABAP development?
First of all, specific requirement, would give you a better answer. As it happens I bumped into this question when working on a program, that uses 3 distinct methods of pseudo-grouping, (while looking for alternatives) and ALL 3 can be used to answer your question, depending on what exactly you need to do. I'm sure there are more ways to do it.
For instance, you can pull maximum values within a group by simply selecting max( your_field ) and grouping by some fields, if that's all you need.
select bname, nation, max( date_from ) from adrp group by bname, nation. "selects highest "from" date for each bname
If you need to use that max value as a filter condition within a query, you can do it by performing pseudo-grouping using sub-query and max within sub-query like this (notice how I move out the BNAME check into sub query, which means I don't have to check both fields using in (subquery) addition):
select ... from adrp as b_adrp "Pulls the latest person info for a user (some conditions are missing, but this is a part of an actual query)
where b_adrp~date_from in (
select max( date_from ) "Highest date_from where both dates are valid
from adrp where persnumber = b_adrp~persnumber and nation = b_adrp~nation and date_from <= #sy-datum )
The query above allows you to select selects all user info from base query and (where the first one only allows to take aggregated and grouped data).
Finally, If you need to check based on composite key and compare it to multiple agregate function results, the implementation will heavily depend on specifics of your requirement (and since your question has none, I'll provide a generic one). Easiest option is to use exists / not exists instead of in (subquery), in exact same way and form the subquery to check for existance of specific key or condition rather than pull a list ( you can nest subqueries if you have to ):
select * from bkpf where exists ( select 1 from bkpf as b where belnr = bkpf~belnr and gjahr = bkpf~gjahr group by belnr, gjahr having max( budat ) = bkpf~budat ) "Took an available example, that I had in testing program.
All 3 queries will get you max value of a column within a group and in fact, all 3 can use joins to achieve identical results.
please find my answers below your questions.
Joining on a subquery is not supported in syntax: SELECT * FROM X as x INNER JOIN ( SELECT ... ) AS y
Putting the subquery in your where condition should do the work SELECT * FROM X AS x INNER JOIN Y AS y ON x~a = y~b WHERE ( SELECT * FROM y WHERE ... )
Using IN for a composite key is not supported in syntax as far as I know: SELECT * FROM X WHERE (key1, key2) IN ( SELECT key1 key2 FROM ... )
You have to split your WHERE clause: SELECT * FROM X WHERE key1 IN ( SELECT key1 FROM y ) AND key2 IN ( SELECT key2 FROM y )
Left join to itself with smaller-than comparison is not supported, outer joins only support EQ comparisons.
Yes, thats right at the moment.
Left join to itself with smaller-than comparison is not supported, outer joins only support EQ comparisons:
SELECT * FROM X AS x LEFT JOIN X as xmax ON x-key1 = xmax-key1 AND x-key2 < xmax-key2 WHERE xmax-key IS INITIAL
This is not true. This SELECT is perfectly valid:
SELECT b1~budat
INTO TABLE lt_bkpf
FROM bkpf AS b1
LEFT JOIN bkpf AS b2
ON b2~belnr < b1~belnr
WHERE b1~bukrs <> ''.
And was valid at least since 7.40 SP08, since July 2013, so at the time you asked this question it was valid as well.