Find the documents which have element in proper "dateTime" format - xquery

I am trying the following query in marklogic-9:
cts:element-value-match(xs:QName("cd:modificationDate"), "[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01].000Z", ("type=dateTime","timezone=TZ"))
to achieve this, but this gives me the following error:
[1.0-ml] XDMP-ARG: cts:element-value-match(xs:QName("cd:modificationDate"), "[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01].000Z", ("type=dateTime", "timezone=TZ")) -- arg2 is invalid
What i want to do is to find out all those documents which conforms to this specific pattern of dateTime. We have a date-range index on this element - modificationDate.
How best can we do this using marklogic and xquery api.

cts:element-value-match is really only useful on string range indexes and even there it only takes simple wildcards (* and ?), not general regular expressions or date formats.
If your range index is a dateTime range index, then every value must conform to the proper xs:dateTime format, so this query would tell you nothing.
This will give you a list of all the URIs where you have a valid dateTime in that element:
cts:uris("", (),
cts:element-range-query(xs:QName("modificationDate"), ">", xs:dateTime("0001-01-01T00:00:00"))
)

Related

Add a day to a datetime project parameter and store in a variable of type datetime in using SSIS expression

I am trying to add a day to a project parameter of type DATETIME and store the results in a variable in SSIS which of type DATETIME.
I am using this below expression in variable
dateadd(day,1,(DT_DATE)(DT_DBDATE) #[$Project::Start_Date])
and getting this below error
TITLE: Expression Builder
Expression cannot be evaluated.
For help, click:
http://go.microsoft.com/fwlink?ProdName=Microsoft%C2%AE%20Visual%20Studio%C2%AE%202015&ProdVer=14.0.23107.0&EvtSrc=Microsoft.DataTransformationServices.Controls.TaskUIFramework.TaskUIFrameworkSR&EvtID=FailToEvaluateExpression&LinkId=20476
------------------------------ ADDITIONAL INFORMATION:
The expression contains unrecognized token "day". If "day" is a
variable, it should be expressed as "#day". The specified token is not
valid. If the token is intended to be a variable name, it should be
prefixed with the # symbol.
Attempt to parse the expression "dateadd(day,1,(DT_DATE)(DT_DBDATE)
#[$Project::Start_Date])" failed and returned error code 0xC00470A4.
The expression cannot be parsed. It might contain invalid elements or
it might not be well-formed. There may also be an out-of-memory error.
(Microsoft.DataTransformationServices.Controls)
------------------------------ BUTTONS:
OK
Can anyone help me to resolve the above problem.
TL;DR;
The argument to the first parameter for dateadd is a string, not a constant/enumeration so it should be
dateadd("day",1,(DT_DATE)(DT_DBDATE) #[$Project::Start_Date])
The long way around
I assume the desire is to get the next day's date with the supplied expression
dateadd(day,1,(DT_DATE)(DT_DBDATE) #[$Project::Start_Date])
When I run into issues with expressions, I break them down into the most atomic statement and then compose from there.
I'm using a SSIS scoped variable instead of a project parameter but the logic will hold true.
I have an SSIS variable, Start_Date of data type DateTime with an initial value of 2022-06-01 09:22 AM (convert that to your current locale's preference for date presenation)
I created a new variable, Start_DateOnly and used the following expression
(DT_DATE)(DT_DBDATE) #[User::Start_Date]
Great, that shows 2022-06-01 (no time component in the Variables window although if you evaluate in the Expression editor, it will show midnight). And the explainer - we convert to the DT_DBDATE datatype to drop the time component but DT_DBDATE is incompatible with the displayed DateTime data type so we explicitly convert to DT_DATE.
Cool beans, now all we need to do is confirm the dateadd function works as expected with our new variable
dateadd(day, 1, #[User::Start_DateOnly])
What the heck?
Expression cannot be evaluated.
The expression contains unrecognized token "day". If "day" is a variable, it should be expressed as "#day". The specified token is not valid. If the token is intended to be a variable name, it should be prefixed with the # symbol.
Oh... yeah, while this language is similar to TSQL, the datepart parameter is a string, not an enum/constant so the syntax should be
dateadd("day", 1, #[User::Start_DateOnly])
Yup, that evaluates to 2022-06-02 12:00 AM

SQLite3 regexp performance

How performant is the SQLite3 REGEXP operator?
For simplicity, assume a simple table with a single column pattern and an index
CREATE TABLE `foobar` (`pattern` TEXT);
CREATE UNIQUE INDEX `foobar_index` ON `foobar`(`pattern`);
and a query like
SELECT * FROM `foobar` WHERE `pattern` REGEXP 'foo.*'
I have been trying to compare and understand the output from EXPLAIN and it seems to be similar to using LIKE except it will be using regexp for matching. However, I am not fully sure how to read the output from EXPLAIN and I'm not getting a grasp of how performant it will be.
I understand it will be slow compared to a indexed WHERE `pattern` = 'foo' query but is it slower/similar to LIKE?
sqlite does not optimize WHERE ... REGEXP ... to use indexes. x REGEXP y is simply a function call; it's equivalent to regexp(x,y). Also note that not all installations of sqlite have a regexp function defined so using it (or the REGEXP operator) is not very portable. LIKE/GLOB on the other hand can take advantage of indexes for prefix queries provided that some additional conditions are met:
The right-hand side of the LIKE or GLOB must be either a string literal or a parameter bound to a string literal that does not begin with a wildcard character.
It must not be possible to make the LIKE or GLOB operator true by having a numeric value (instead of a string or blob) on the left-hand side. This means that either:
the left-hand side of the LIKE or GLOB operator is the name of an indexed column with TEXT affinity, or
the right-hand side pattern argument does not begin with a minus sign ("-") or a digit.
This constraint arises from the fact that numbers do not sort in lexicographical order. For example: 9<10 but '9'>'10'.
The built-in functions used to implement LIKE and GLOB must not have been overloaded using the sqlite3_create_function() API.
For the GLOB operator, the column must be indexed using the built-in BINARY collating sequence.
For the LIKE operator, if case_sensitive_like mode is enabled then the column must indexed using BINARY collating sequence, or if case_sensitive_like mode is disabled then the column must indexed using built-in NOCASE collating sequence.
If the ESCAPE option is used, the ESCAPE character must be ASCII, or a single-byte character in UTF-8.

Xquery Where clause not working when using nested query

Good Day,
I'm new to xquery.
I'm trying to execute xquery with a where clause that returns the values greater than a value returned from a nested query as show below. It runs but returns values that are not greater than the returned value
If I use the where clause directly with the value it works fine. I'm using BaseX to execute my query. Appreciate any feedback, I believe the parser may be reading my subquery wrong.
for $y in doc("url.xml")/taxi_stations/stand
where $y/taxis>=
(
for $x in doc("url.xml")/taxi_stations/stand
where $x/name="Jacksonville"
return data($x/taxis)
)
return ($y/taxis,$y/name)
What is the value of $taxis? It's possible your comparisons are happening on strings, not numbers.
In your nested return, you call data() on $x/taxis - assuming that correctly returns a number value, then $y/taxis in your outer where clause should probably also be wrapped in data().
However, if there is no schema on your document, then data() will simply return a string. In that case you should convert your taxis element to a number using fn:number() or directly casting it like $y/taxis/xs:integer(.).

How can I prevent SQLite from treating a string as a number?

I would like to query an SQLite table that contains directory paths to find all the paths under some hierarchy. Here's an example of the contents of the column:
/alpha/papa/
/alpha/papa/tango/
/alpha/quebec/
/bravo/papa/
/bravo/papa/uniform/
/charlie/quebec/tango/
If I search for everything under /bravo/papa/, I would like to get:
/bravo/papa/
/bravo/papa/uniform/
I am currently trying to do this like so (see below for the long story of why I can't use more simple methods):
SELECT * FROM Files WHERE Path >= '/bravo/papa/' AND Path < '/bravo/papa0';
This works. It looks a bit weird, but it works for this example. '0' is the unicode code point 1 greater than '/'. When ordered lexicographically, all the paths starting with '/bravo/papa/' compare greater than it and less than 'bravo/papa0'. However, in my tests, I find that this breaks down when we try this:
SELECT * FROM Files WHERE Path >= '/' AND Path < '0';
This returns no results, but it should return every row. As far as I can tell, the problem is that SQLite is treating '0' as a number, not a string. If I use '0Z' instead of '0', for example, I do get results, but I introduce a risk of getting false positives. (For example, if there actually was an entry '0'.)
The simple version of my question is: is there some way to get SQLite to treat '0' in such a query as the length-1 string containing the unicode character '0' (which should sort strings such as '!', '*' and '/', but before '1', '=' and 'A') instead of the integer 0 (which SQLite sorts before all strings)?
I think in this case I can actually get away with special-casing a search for everything under '/', since all my entries will always start with '/', but I'd really like to know how to avoid this sort of thing in general, as it's unpleasantly surprising in all the same ways as Javascript's "==" operator.
First approach
A more natural approach would be to use the LIKE or GLOB operator. For example:
SELECT * FROM Files WHERE Path LIKE #prefix || '%';
But I want to support all valid path characters, so I would need to use ESCAPE for the '_' and '%' symbols. Apparently this prevents SQLite from using an index on Path. (See http://www.sqlite.org/optoverview.html#like_opt ) I really want to be able to benefit from an index here, and it sounds like that's impossible using either LIKE or GLOB unless I can guarantee that none of their special characters will occur in the directory name, and POSIX allows anything other than NUL and '/', even GLOB's '*' and '?' characters.
I'm providing this for context. I'm interested in other approaches to solve the underlying problem, but I'd prefer to accept an answer that directly addresses the ambiguity of strings-that-look-like-numbers in SQLite.
Similar questions
How do I prevent sqlite from evaluating a string as a math expression?
In that question, the values weren't quoted. I get these results even when the values are quoted or passed in as parameters.
EDIT - See my answer below. The column was created with the invalid type "STRING", which SQLite treated as NUMERIC.
* Groan *. The column had NUMERIC affinity because it had accidentally been specified as "STRING" instead of "TEXT". Since SQLite didn't recognize the type name, it made it NUMERIC, and because SQLite doesn't enforce column types, everything else worked as expected, except that any time a number-like string is inserted into that column it is converted into a numeric type.

TALES expression to compare numeric input in Plone?

TALES expression is new to me. Can I get some good reference for the same? Actually I wish to define a content rule for numeric input field using ploneformgen. Something like:
python: request.form.get('amt', False) <= 5000
then apply the rule.
Here 'amt' is a numeric/whole number field on the input form.
For reference, you should look at the official TALES specification, or refer to the TALES section of the Zope Page Templates reference.
In this case, you are using a plain python expression, and thus the normal rules of python code apply.
The expression request.form.get('amt', False) would return the request parameter 'amt' from the request, and if that's missing, return the boolean False, which you then compare to an integer value.
There are 2 things wrong with that expression: first of all you assume that the 'amt' parameter is an integer value. Even a PFG integer field however, is still a string in the request object. As such you'll need to convert in to an integer first before you can compare it.
Also, you fall back to a boolean, which in integer comparisons will be regarded as the equivalent of 0, better be explicit and use that instead:
python: int(request.form.get('amt', 0)) <= 5000
Note that for a PFG condition, you can also return a string error message instead of boolean True:
python: int(request.form.get('amt', 0)) <= 5000 or 'Amount must be not be greater than 5000'
Usually form parameters are passed in as strings if they are not defined on the application level otherwise e.g.
Zope will under the hood use the fieldname amt:int in order to convert the value to an integer.
So you may want to try to put an int(....) around the first expression.

Resources