Regular Expressions in DB2 SQL - sql

(Other than using a UDF) Any REGEXP-In-SQL support for DB2 9.7 ?

Starting with DB2 11.1 there is built-in regex support. One of the new function is REGEXP_SUBSTR and there are some more.
SELECT REGEXP_SUBSTR('hello to you', '.o',1,1)
FROM sysibm.sysdummy1

I'm komikoni(Keisuke Konishi).
I created the regular expression function (UDF) which does not exist in db2.
The UDF using the SQL/XML(Xquery).
You can easily install.
List of regular expressions provide UDF
REG_MATCHES
provides Coincidence existence ( Scalar )
REG_REPLACE
string substitution ( Scalar )
REG_COUNT
number of matches retrieved ( Scalar )
REG_POSITION
match position acquisition ( Scalar )
REG_SUBSTR
gets a string matching ( Scalar )
REG_SUBSTR_TABLE
list of matching string information ( Table )
REG_TOKENIZE_TABLE
list of mismatched string information (divided by a separator string) ( Table )
REG_ALLTOKEN_TABLE
list of mismatch string and matching string information ( Table )
Scripts can be downloaded from here.
(Sorry in Japanese)
https://www.ibm.com/developerworks/jp/data/library/db2/j_d-regularexpression/
(English : Machine translation Script : The last of a Japanese page)
I look forward to your feedback and comments.

The real answer is that DB2 does support regular expression since PureXML was added (v9.7 included) via xQuery with the matches function.
For example:
db2 "with val as (
select t.text
from texts t
where xmlcast(xmlquery('fn:matches(\$TEXT,''^[A-Za-z 0-9]*$'')') as integer) = 0
)
select * from val"
For more information:
http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.xml.doc/doc/xqrfnmat.html

That works fine except for DB2 z/OS - in DB2 v10 z/OS you must use PASSING as follows
with val as (
select t.text
from texts t
where xmlcast(xmlquery('fn:matches($v,"^[A-Za-z 0-9]*$")'
PASSING t.text as "v" ) as integer) = 0
)
select * from val

There is no built-in support for regular expressions in DB2 9.7.
The only way is using UDFs or table functions as described in the article 'OMG Ponies' added in the comment.
#dan1111: I do not appreciate my post being edited, especially if people can't read the question correctly. The OP asked Any REGEXP-In-SQL support for DB2 9.7
SQL is not XQuery !!!
Sorry, don't delete the text of my 100% correct answer. You can add a comment or write your own answer.

Related

JSON_EXTRACT How to extract value of a dynamic key

The below returns value of key 'a', i.e. "x". This is good if one already knows the key name.
SELECT JSON_EXTRACT('{"a":"x", "b":"y"}', "$['a']") as val
In my use case, the key name is dynamic. Hence, above wouldn't help. Is there anyway to extract first child element only without mentioning key-name 'a' in standard SQL?
#standardSQL
SELECT REGEXP_EXTRACT('{"a":"x", "b":"y"}', r'^{"\w":"(\w)",') AS val
Mikhail proposes a good compromise to solve this within SQL, but sometimes a regular expression can't parse complex JSON objects.
You could do anything operation within a JSON object by leveraging Javascript with a BigQuery SQL query.
For example:
#standardSQL
CREATE TEMPORARY FUNCTION anyJsonOp(json STRING, langs STRING)
RETURNS STRING
LANGUAGE js AS """
lang = JSON.parse(json).pull_request.base.repo.language;
if (langs.split(",").indexOf(lang)>-1) {
return lang
}
""";
SELECT anyJsonOp(payload, langs), COUNT(*)
FROM `githubarchive.day.20171010` a
CROSS JOIN (SELECT 'JavaScript,Java,Python,Ruby' langs)
WHERE type='PullRequestEvent'
GROUP BY 1
ORDER BY 2 DESC

Can I convert centigrade to farenheit in a query (not a function)

In Oracle I can convert centigrade to farenheit in an SQL query, see below. It seems SQL Server does not have full regex functionality. Is it possible to do this without dropping into a function, which I currently do?
(UNISTR('00B0') is the degree symbol we use)
The requirement is for any string that contains [digits]°C to be converted to same string with [new_digits]°F.
SELECT replace(replace(v_text_f,replace(regexp_substr(v_text_f,'\-? [[:digit:]]+\.?[[:digit:]]*'||UNISTR('\00B0')||'C'),UNISTR('\00B0')||'C'),
replace(regexp_substr(v_text_f,'\-?[[:digit:]]+\.?[[:digit:]]*'||UNISTR('\00B0')||'C'),UNISTR('\00B0')||'C')*9/5+32||UNISTR('\00B0')||'F'),
UNISTR('\00B0')||'F'||UNISTR('\00B0')||'C',UNISTR('\00B0') ||'F')
FROM (SELECT '38'||UNISTR('\00B0')||'C' as v_text_f FROM DUAL)
Try this, comparing to Oracle code, extremely simplified version:
DECLARE #C nvarchar(10) = '38'+CHAR(0x00B0)+'C' --38°C
SELECT CONVERT(nvarchar(10),CONVERT(int ,LEFT(#C, CHARINDEX(CHAR(0x00B0), #C)-1))*9/5+32)+CHAR(0x00B0)+'F'
--100°F

BigQuery Wildcard using TABLE_DATE_RANGE()

Great news about the new table wildcard functions this morning! Is there a way to use TABLE_DATE_RANGE() on tables that include date but no prefix?
I have a dataset that contains tables named YYYYMMDD (no prefix). Normally I would query like so:
SELECT foo
FROM [mydata.20140319],[mydata.20140320],[mydata.20140321]
LIMIT 100
I tried the following but I'm getting an error:
SELECT foo
FROM
(TABLE_DATE_RANGE(mydata.,
TIMESTAMP('2014-03-19'),
TIMESTAMP('2015-03-21')))
LIMIT 100
as well as:
SELECT foo
FROM
(TABLE_DATE_RANGE(mydata,
TIMESTAMP('2014-03-19'),
TIMESTAMP('2015-03-21')))
LIMIT 100
The underlying bug here has been fixed as of 2015-05-14. You should be able to use TABLE_DATE_RANGE with a purely numeric table name. You'll need to end the dataset in a '.' and enclose the name in brackets, so that the parser doesn't complain. This should work:
SELECT foo
FROM
(TABLE_DATE_RANGE([mydata.],
TIMESTAMP('2014-03-19'),
TIMESTAMP('2015-03-21')))
LIMIT 100
Note: The underlying bug has been fixed, please see my other answer.
Original response left for posterity (since the workaround should still work, in case you need it for some reason)
Great question. That should work, but it doesn't currently. I've filed an internal bug. In the meantime, a workaround is to use the TABLE_QUERY function, as in:
SELECT foo
FROM (
TABLE_QUERY(mydata,
"TIMESTAMP(table_id) BETWEEN "
+ "TIMESTAMP('2014-03-19') "
+ "AND TIMESTAMP('2015-03-21')"))
Note that with standard SQL support in BigQuery, you can use _TABLE_SUFFIX, instead of TABLE_QUERY. For example:
SELECT foo
FROM `mydata_*`
WHERE _TABLE_SUFFIX BETWEEN '20140319' AND '20150321'
Also check this question for more about BigQuery standard SQL.

how to return the value of a scalar function in db2

I have a db2 function returning an integer. As per my limited knowledge the only way to see this function working is using to return column in a query like the example below.
Is there a way to display a return value of a function given a parameter withoyt building up a more complex query?
Example
I have a function
myfoo(index integer) returns integer ...
And I am using it in a more complex quewry like
select myIndex, myfoo(myIndex), myValue from MyTable...
If I try to get the following
select from myfoo(3)
it will not work.
Is there any db2 function to print out the return value of that function without error?
SELECT myfoo(3) FROM SYSIBM.SYSDUMMY1
SYSIBM.SYSDUMMY1 is a special "dummy" table that contains a single row, the equivalent of Oracle's DUAL.
If you have the compatibility vector, you can even use Oracle's Dual table. http://pic.dhe.ibm.com/infocenter/db2luw/v10r5/topic/com.ibm.db2.luw.apdv.porting.doc/doc/r0052874.html
Also, you can use the 'values' sentence. For example,
values myfoo(myIndex)

Implement an IN Query using XQuery in MSSQLServer 2005

I'm trying to query an xml column using an IN expression. I have not found a native XQuery way of doing such a query so I have tried two work-arounds:
Implement the IN query as a concatenation of ORs like this:
WHERE Data.exist('/Document/ParentKTMNode[text() = sql:variable("#Param1368320145") or
text() = sql:variable("#Param2043685301") or ...
Implement the IN query with the String fn:contains(...) method like this:
WHERE Data.exist('/Document/Field2[fn:contains(sql:variable("#Param1412022317"), .)]') = 1
Where the given parameter is a (long) string with the values separated by "|"
The problem is that Version 1. doesn't work for more than about 50 arguments. The server throws an out of memory exception. Version 2. works, but is very, very slow.
Has anyone a 3. idea? To phrase the problem more complete: Given a list of values, of any sql native type, select all rows whose xml column has one of the given values at a specific field in the xml.
Try to insert all your parameters in a table and query using sql:column clause:
SELECT Mytable.Column FROM MyTable
CROSS JOIN (SELECT '#Param1' T UNION ALL SELECT '#Param2') B
WHERE Data.exist('/Document/ParentKTMNode[text() = sql:column("T")