How to manipulate multi-value string parameters for a SQL Command in Crystal Reports - sql

I have a Crystal Report based on a SQL Command that, in part, consists of procedure names. What I'm trying to do is add a multi-value string parameter to the SQL Command such that the end users can enter partial procedure names and the report will return only those relevant procedures that string match.
For example, a user should be able to enter "%KNEE%" and "%HIP%" into the parameter and return all procedures that contain the words "KNEE" and "HIP". The problem is that I can't figure out how to manipulate the parameter value in the SQL to accomplish this. I've done this before with a report parameter (as opposed to a SQL Command parameter) by simply adding the line {table.procedure_name} like {?name match parameter} to the record selection formula, but taking the same approach in the SQL Command gets me an "ORA-00907: Missing right parenthesis" error.
Any suggestions on how I can manipulate the multi-value string parameter to accomplish this?

I dont like to post this as an answer because I don't care for the solution however it is the only way I have found to work around this.
I have had to instruct users to enter '%KNEE%','%HIP%','%ETC%' at the parameter prompt. Then the {table.procedure_name} like {?name match parameter} should work in your SQL. Not optimal, especially for your scenario with the %. I would love to hear someone provide a better solution because I have wrestled with this many times.

Here's an approach:
SELECT column0
FROM table0
INNER JOIN (
SELECT trim('%' || x.column_value.extract('e/text()') || '%') SEARCH
FROM ( SELECT 'arm,knee' options FROM dual ) t,
TABLE (xmlsequence(xmltype('<e><e>' || replace(t.options,',','</e><e>')|| '</e></e>').extract('e/e'))) x
) v ON column0 LIKE v.search
Use Oracle's XML functionality to convert a comma-delimited string to an equivalent number of rows, wrapping each clause with %%. Then join those rows to the desired table.
To use with CR, create a single-value, string parameter and add it to the code:
...
FROM ( SELECT '{?search_param}' options FROM dual ) t,
...

Related

How can you filter Snowflake EXPLAIN AS TABULAR syntax when its embedded in the TABLE function? Can you filter it with anything?

I have a table named Posts I would like to count and profile in Snowflake using the current Snowsight UI.
When I return the results via EXPLAIN using TABLULAR I am able to return the set with the combination of TABLE, RESULT_SCAN, and LAST_QUERY_ID functions, but any predicate or filter or column reference seems to fail.
Is there a valid way to do this in Snowflake with the TABLE function or is there another way to query the output of the EXPLAIN using TABLULAR?
-- Works
EXPLAIN using TABULAR SELECT COUNT(*) from Posts;
-- Works
SELECT t.* FROM TABLE(RESULT_SCAN(LAST_QUERY_ID())) as t;
-- Does not work
SELECT t.* FROM TABLE(RESULT_SCAN(LAST_QUERY_ID())) as t where operation = 'GlobalStats';
-- invalid identifier 'OPERATION', the column does not seem recognized.
Tried the third example and expected the predicate to apply to the function output. I don't understand why the filter works on some TABLE() results and not others.
You need to double quote the column name
where "operation"=
From the Documentation
Note that because the output column names from the DESC USER command
were generated in lowercase, the commands use delimited identifier
notation (double quotes) around the column names in the query to
ensure that the column names in the query match the column names in
the output that was scanned

Using Regex to determine what kind of SQL statement a row is from a list?

I have a large list of SQL commands such as
SELECT * FROM TEST_TABLE
INSERT .....
UPDATE .....
SELECT * FROM ....
etc. My goal is to parse this list into a set of results so that I can easily determine a good count of how many of these statements are SELECT statements, how many are UPDATES, etc.
so I would be looking at a result set such as
SELECT 2
INSERT 1
UPDATE 1
...
I figured I could do this with Regex, but I'm a bit lost other than simply looking at everything string and comparing against 'SELECT' as a prefix, but this can run into multiple issues. Is there any other way to format this using REGEX?
You can add the SQL statements to a table and run them through a SQL query. If the SQL text is in a column called SQL_TEXT, you can get the SQL command type using this:
upper(regexp_substr(trim(regexp_replace(SQL_TEXT, '\\s', ' ')),
'^([\\w\\-]+)')) as COMMAND_TYPE
You'll need to do some clean up to create a column that indicates the type of statement you have. The rest is just basic aggregation
with cte as
(select *, trim(lower(split_part(regexp_replace(col, '\\s', ' '),' ',1))) as statement
from t)
select statement, count(*) as freq
from cte
group by statement;
SQL is a language and needs a parser to turn it from text into a structure. Regular expressions can only do part of the work (such as lexing).
Regular Expression Vs. String Parsing
You will have to limit your ambition if you want to restrict yourself to using regular expressions.
Still you can get some distance if you so want. A quick search found this random example of tokenizing MySQL SQL statements using regex https://swanhart.livejournal.com/130191.html

Oracle SQL Stored Procedure with Oracle reserved words passed to variable

I have a stored procedure that gets passed a string of values separated with spaces, which then does a search in the table and returns data where a column has any of those values. All went well until a user needed to pass 'INDEX END UNKNOWN PROCESS' which didn't return anything, even though there is data with those values:
CREATE OR REPLACE PROCEDURE Searches
(
QUEUE IN TYPES.CHAR50,
P_CURSOR IN OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN P_CURSOR FOR
SELECT *
FROM tablez t
WHERE /* If the subquery returns UNKNOWN, END, PROCESS, INDEX which are Oracle reserved words the main query won't return any results */
/* In order to pass this inconsistency, I concatenated XYZ to both sides when using IN Clause */
CONCAT(LTRIM(RTRIM(t.QUEUECD)),'XYZ') IN ( SELECT CONCAT(LTRIM(RTRIM(tr.prom)),'XYZ')
FROM ( SELECT regexp_substr(QUEUE,'[^ ]+', 1, LEVEL) prom
FROM dual
CONNECT BY regexp_substr(QUEUE, '[^ ]+', 1, LEVEL) IS NOT NULL
) tr
)
;
END Searches;
So, I changed the code to use regexp_substr, and only concatenating 'XYZ' returned values when doing the comparison. But this is a temporary fix, because QUEUECD is an indexed column in the database and using CONCAT in WHERE clause led to performance issues, on big data.
Do you have any suggestions how to improve the performance or pass the list of values in a different way?
Thank you!
Oracle SQL Stored Procedure with Oracle reserved words passed to
variable
It looks like a different problem. Look: there is no way to pass "reserved words" as a value of variable - when you've got varchar variable then the value is a text - nothing more.
I've made a sample table and tested a query without concatenation 'XYZ' - and I don't have such problems. Maybe there are some white, non-printable characters at the end or beginning in records??
Regarding to:
Do you have any suggestions how to improve the performance or pass the list of values in a different way?
Yes. Pass collection (nested table) as parameter. For example:
create or replace type T_TAB_STRING as table of varchar2(4000);
Next, change type of QUEUE from TYPES.CHAR50 to T_TAB_STRING.
Then you can use table() expression to unnest collection inside query like that:
SELECT *
FROM tablez t
WHERE t.QUEUECD IN ( SELECT /*+ DYNAMIC_SAMPLING(tr, 2) */
*
FROM TABLE(QUEUE) tr
)
;
The dynamic sampling hint is for forcing DB to check how many elements is inside collection. Without that DB assume it is the size of 1 block (usually 8k), so CBO could choose to do full scan instead of index scan.
If you cannot use that hint, or it doesn't work for some reason, there is other way to help CBO with collections in queries. It's implementing Extensible Optimiser interface for that collection. It has been written by Adrian Billington in this article how to do it.

SQL - just view the description for explanation

I would like to ask if it is possible to do this:
For example the search string is '009' -> (consider the digits as string)
is it possible to have a query that will return any occurrences of this on the database not considering the order.
for this example it will return
'009'
'090'
'900'
given these exists on the database. thanks!!!!
Use the Like operator.
For Example :-
SELECT Marks FROM Report WHERE Marks LIKE '%009%' OR '%090%' OR '%900%'
Split the string into individual characters, select all rows containing the first character and put them in a temporary table, then select all rows from the temporary table that contain the second character and put these in a temporary table, then select all rows from that temporary table that contain the third character.
Of course, there are probably many ways to optimize this, but I see no reason why it would not be possible to make a query like that work.
It can not be achieved in a straight forward way as there is no sort() function for a particular value like there is lower(), upper() functions.
But there is some workarounds like -
Suppose you are running query for COL A, maintain another column SORTED_A where from application level you keep the sorted value of COL A
Then when you execute query - sort the searchToken and run select query with matching sorted searchToken with the SORTED_A column

Selection based on string containing one or many other strings

I have a table 'forms' with a column 'title'.
Inside my stored procedure I create a temp table '#temp1' with the column 'searchVals'.
Multiple strings are parsed into the stored procedure, the number of strings is variable.
What I'm trying to achieve is selecting a row if the 'title' contains one or many 'searchVal'. But I haven't been able to achieve this successfully yet.
For example something like this
SELECT title FROM #temp1 WHERE title IN ('%'+(SELECT searchVal FROM #temp1)+'%')
The issue is obviously that IN doesn't allow wildcards but if it did, this is the type of result I'm trying to achieve.
Stacking ORs also doesn't work as the number of rows in #temp1 is variable.
Predicate and free-text searches don't work as the forms database isn't indexed appropriately.
I've come up with what I think is a valid solution but I can't seem to construct it correctly. The function would be called from the WHERE clause and return a boolean. I'm sorry if this has been answered elsewhere, I did search extensively.
Below is my proposed solution with pseudocode code where I'm not sure of the interchangeable SQL code.
DECLARE FUNCTION dbo.checkVal(searchVal column, formTitle varchar)
RETURNS boolean
AS
BEGIN
WHILE (not end of column)
IF formTitle LIKE '%'+searchVal+'%'
RETURN true
END
END
RETURN FALSE
END
Sorry for my inconsistent and incorrect SQL code. I would appreciate any suggestions or corrections that would make my code work. Better solutions are welcome too.
Thank you.
How about to check every row of forms by an EXISTS()?
SELECT *
FROM forms f
WHERE EXISTS
(
SELECT *
FROM #temp1
WHERE f.title LIKE '%' + searchVals + '%'
)
You can use the LIKE operator in a JOIN statement:
SELECT DISTINCT f.*
FROM forms f
JOIN #temp1 t ON f.title LIKE '%' + t.column + '%'
But keep in mind that using the LIKE operator does come with a performance hit so you will want to reduce the number of rows in the forms table using a where clause if possible