Doctrine and Oracle REGEXP_LIKE - regex

I'm using Doctrine in combination with an Oracle database. I use platform-specific features heavily, so I already created a bunch of custom DQL functions. But now I ran into a serious problem. To do a LIKE query with a regular expression, Oracle offers the REGEXP_LIKE operator. It looks like a function, but really acts as a relational operator. Unfortunately, Doctrine only allows me to create custom functions, not operators. I cannot use it like a function, because Doctrine requires me to make it a complete expression, e.g. REGEXP_LIKE(foo, bar) != 0. But for Oracle that's a syntax error.
As a workaround, I use this contraption in the getSql method of my custom DQL function:
CASE REGEXP_LIKE(foo, bar) THEN 1 ELSE 0 END
Looks ugly, though. Is there a better way to get this working in Doctrine??

regexp_like in Oracle is only allowed in the criteria part of the SQL statement; but what you can use is the true Oracle function regexp_count in a case clause:
select col1, col2, -- etc
case (regexp_count(col3, '^Hey$'))
when 0 then 0
else 1
end as found
from table;
So for your example REGEXP_LIKE(foo, bar) != 0 would become REGEXP_COUNT(foo, bar) != 0

Related

Bigquery struct introspection

Is there a way to get the element types of a struct? For example something along the lines of:
SELECT #TYPE(structField.y)
SELECT #TYPE(structField)
...etc
Is that possible to do? The closest I can find is via the query editor and the web call it makes to validate a query:
As I mentioned already in comments - one of the option is to mimic same very Dry Run call with query built in such a way that it will fail with exact error message that will give you the info you are looking for. Obviously this assumes your use case can be implemented in whatever scripting language you prefer. Should be relatively easy to do.
Meantime, I was looking for making this within the SQL Query.
Below is the example of another option.
It is limited to below types, which might fit or not into your particular use case
object, array, string, number, boolean, null
So example is
select
s.birthdate, json_type(to_json(s.birthdate)),
s.country, json_type(to_json(s.country)),
s.age, json_type(to_json(s.age)),
s.weight, json_type(to_json(s.weight)),
s.is_this, json_type(to_json(s.is_this)),
from (
select struct(date '2022-01-01' as birthdate, 'UA' as country, 1 as age, 2.5 as weight, true as is_this) s
)
with output
You can try the below approach.
SELECT COLUMN_NAME, DATA_TYPE
FROM `your-project.your-dataset.INFORMATION_SCHEMA.COLUMNS`
WHERE TABLE_NAME = 'your-table-name'
AND COLUMN_NAME = 'your-struct-column-name'
ORDER BY ORDINAL_POSITION
You can check this documentation for more details using INFORMATION_SCHEMA for BigQuery.
Below is the screenshot of my testing.
DATA:
RESULT USING THE ABOVE SYNTAX:

vc++ (sqlite)how to distingush statement is SELECT - or NOT?

My code is necessary to distinguish whether Sql statement is SELECT or not.
If the result is more than 1, it is easy to distinguish select.
But there is no result when the statement executed, how do I distinguish it?
sqlite_stmt *some_stmt;
//case 1 : (the table has no row)
sqlite3_prepare("select * from some_table", &some_stmt);
//case 2 :
sqlite3_prepare("create table some_table2", &some_stmt);
int result = sqlite3_step(some_stmt);
result is same :
SQLITE_DONE;
I can distinguish it with two method,
1st is get substring from the statement. but i don't want do it, it seems to be incorrectly way.
2st is use sqlite3_column_count(). Usually column_count has one or more than if the statement is SELECT.
Is it correct way using sqlite3_coulmn_count()? Isn't there anything that No-column-table in sqlite or etc?
I want correct way to distinguish whether Statement is SELECT or Not.
There are other statements that return data (e.g., some PRAGMAs), so you cannot search for "SELECT".
As documented, sqlite3_column_count() is the correct way:
This routine returns 0 if pStmt is an SQL statement that does not return data (for example an UPDATE).
In SQL, there is no such thing as a table without columns. Even in a construct that does not actually look at any data (such as EXISTS (SELECT ...)), you have to use some dummy column(s).

How to load custom sql functions with django

I am trying to use Django's initial SQL data functionality to create an SQL function. The docs state I can do this:
https://docs.djangoproject.com/en/1.6/howto/initial-data/#providing-initial-sql-data
Django provides a hook for passing the database arbitrary SQL that’s executed just after the CREATE TABLE statements when you run migrate. You can use this hook to populate default records, or you could also create SQL functions, views, triggers, etc.
After some googling I found that django's customsql code splits any sql files and runs them line by line, creating this error,
Failed to install custom SQL for myapp.somemodel model: unterminated dollar-quoted string at or near "$$ BEGIN;"
Is there an accepted work around for this? Or a better way to load custom sql functions?
Yeah, I've seen this problem before. If you stick a multi-line function in your app's sql/<modelname>.sql like so:
CREATE OR REPLACE FUNCTION increment(i integer) RETURNS integer AS $$
BEGIN
RETURN i + 1;
END;
$$ LANGUAGE plpgsql;
you'll get the error you saw, namely something like:
Failed to install custom SQL for mysite.Poll model: unterminated dollar-quoted string at or near "$$ BEGIN RETURN i + 1;"
LINE 1: ... FUNCTION increment(i integer) RETURNS integer AS $$ BEGIN R...
I think you should be able to work around the problem by squeezing the function definition all onto one line, e.g.
CREATE OR REPLACE FUNCTION increment(i integer) RETURNS integer AS $$BEGIN RETURN i + 1; END; $$ LANGUAGE plpgsql;
Looks like this bug affects any multi-line functions (both dollar-quoted and single-quoted). I tested on Django 1.6, no idea if it's been fixed already.

Concat strings in SQL Server and Oracle with the same unmodified query

I have a program that must support both Oracle and SQL Server for it's database.
At some point I must execute a query where I want to concatenate 2 columns in the select statement.
In SQL Server, this is done with the + operator
select column1 + ' - ' + column2 from mytable
And oracle this is done with concat
select concat(concat(column1, ' - '), column2) from mytable
I'm looking for a way to leverage them both, so my code has a single SQL query literal string for both databases and I can avoid ugly constructs where I need to check which DBMS I'm connected to.
My first instinct was to encapsulate the different queries into a stored procedure, so each DBMS can have their own implementation of the query, but I was unable to create the procedure in Oracle that returns the record set in the same way as SQL Server does.
Update: Creating a concat function in SQL Server doesn't make the query compatible with Oracle because SQL Server requires the owner to be specified when calling the function as:
select dbo.concat(dbo.concat(column1), ' - '), column2) from mytable
It took me a while to figure it out after creating my own concat function in SQL Server.
On the other hand, looks like a function in Oracle with SYS_REFCURSOR can't be called with a simple
exec myfunction
And return the table as in SQL Server.
In the end, the solution was to create a view with the same name on both RDBMs but with different implementations, then I can do a simple select on the view.
If you want to go down the path of creating a stored procedure, whatever framework you're using should be able to more or less transparently handle an Oracle stored procedure with an OUT parameter that is a SYS_REFCURSOR and call that as you would a SQL Server stored procedure that just does a SELECT statement.
CREATE OR REPLACE PROCEDURE some_procedure( p_rc OUT sys_refcursor )
AS
BEGIN
-- You could use the CONCAT function rather than Oracle's string concatenation
-- operator || but I would prefer the double pipes.
OPEN p_rc
FOR SELECT column1 || ' - ' || column2
FROM myTable;
END;
Alternatively, you could define your own CONCAT function in SQL Server.
Nope, sorry.
As you've noted string concatentaion is implemented in SQL-Server with + and Oracle with concat or ||.
I would avoid doing some nasty string manipulation in stored procedures and simply create your own concatenation function in one instance or the other that uses the same syntax. Probably SQL-Server so you can use concat.
The alternative is to pass + or || depending on what RDBMS you're connected to.
Apparently in SQL Server 2012 they have included a CONCAT() function:
http://msdn.microsoft.com/en-us/library/hh231515.aspx
If you are trying to create a database agnostic application, you should stick to either
Stick to very basic SQL and do anything like this in your application.
Create different abstractions for different databases. If you hope to get any kind of scale out of your application, this is the path you'll likely need to take.
I wouldn't go down the stored procedure path, you can probably get it to work, but but week you'll find out you need to support "database X", then you'll need to rewrite your stored proc in that database as well. Its a recipe for pain.

Case sensitive LINQ to DataSet

I am having an issue with a strongly typed DataSet exhibiting case-sensitivity using LINQ to DataSet to retrieve and filter data. In my example project, I have created a strongly typed DataSet called DataSet1. It contains a single DataTable called Customers. To instantiate and populate, I create a couple of rows (notice the casing on the names):
// Instantiate
DataSet1 ds = new DataSet1();
// Insert data
ds.Customers.AddCustomersRow(1, "Smith", "John");
ds.Customers.AddCustomersRow(2, "SMith", "Jane");
Next, I can easily fetch/filter using the DataSet's built-in Select functionality:
var res1 = ds.Customers.Select("LastName LIKE 'sm%'");
Console.WriteLine("DataSet Select: {0}", res1.Length);
DataSet Select: 2
The trouble begins when attempting to use LINQ to DataSet to perform the same operation:
var res2 = from c in ds.Customers where c.LastName.StartsWith("sm") select c;
Console.WriteLine("LINQ to DataSet: {0}", res2.Count());
LINQ to DataSet: 0
I've already checked the instantiated DataSet's CaseSensitive property as well as the Customer DataTable's CaseSensitive property--both are false. I also realize that when using the Select methodology, the DataSet performs the filtering and the LINQ query is doing something else.
My hope and desire for this type of code was to use it to Unit Test our Compiled LINQ to SQL queries so I can't really change all the current queries to use:
...where c.LastName.StartsWith("sm", StringComparison.CurrentCultureIgnoreCase) select c;
...as that changes the query in SQL. Thanks all for any suggestions!
LINQ to DataSets still use normal managed functions, including the standard String.StartsWith method.
It is fundamentally impossible for these methods to be aware of the DataTable's CaseSensitive property.
Instead, you can use an ExpressionVisitor to change all StartsWith (or similar) calls to pass StringComparison.CurrentCultureIgnoreCase.
You could also use c.LastName.ToLower().StartsWith("sm" which will make sure you also retrieve lower cased entries. Good luck!