Translate SPARQL to SQL - mysql

I would like to know if there is a way to obtain the SQL query starting from a SPARQL query.
For example, I have this SPARQL query:
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX ub: <http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#>
SELECT ?X
WHERE {
?X rdf:type ub:GraduateStudent .
?X ub:takesCourse <http://www.Department0.University0.edu/GraduateCourse0>
}
I would like to obtain something like this (the triples are stored in a table triples(subject, predicate, object):
SELECT subject
FROM triples
WHERE predicate = "<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>"
AND object = "<http://swat.cse.lehigh.edu/onto/univ-bench.owl#GraduateStudent>"
AND subject IN (
SELECT subject
FROM triples
WHERE predicate = "<http://swat.cse.lehigh.edu/onto/univ-bench.owl#takesCourse>"
AND object = "<http://www.Department0.University0.edu/GraduateCourse0>"
)
or
SELECT subject
FROM triples
WHERE predicate = "<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>"
AND object = "<http://swat.cse.lehigh.edu/onto/univ-bench.owl#GraduateStudent>"
INTERSECT
SELECT subject
FROM triples
WHERE predicate = "<http://swat.cse.lehigh.edu/onto/univ-bench.owl#takesCourse>"
AND object = "<http://www.Department0.University0.edu/GraduateCourse0>"
Thank you in advance!

Apache Jena used to provide SQL storage : see https://github.com/apache/jena/tree/main/jena-sdb on how to get the old code. It translates basic graph patterns using JOIN and OPTIONAL with LEFT JOIN.
It has its own database layout with RDF terms in a dictionary. There was also a simple scheme with strings and a single triples table - that is not efficient in practice. See also the very old "RDB" Jena storage which was in the pre-Apache project.
There are also various papers on the web discussing this topic.

Related

MySQL using JSON_ARRAYAGG in a SELECT IN clause?

Our database solution is very JSON heavy, and as such, our SQL queries are all JSON based (for the most part). This includes extensive use of JSON_ARRAYAGG().
The problem I'm encountering is using a returned array of indexes in WHERE IN, which simply doesn't work. From what I can tell it's a simple formatting issue where MySQL wants an () encapsulation and a JSON array is a [] encapsulation.
For example:
SELECT COUNT(si.ID) AS item_count, JSON_ARRAYAGG(si.ID) AS item_array
FROM sourcing_item si;
Returns:
7, [1,2,3,4,5,6,7]
What I need to do is write a complex nested query that allows for selecting record IDs that are IN the JSON_ARRAYAGG result. Like:
SELECT si.item_name
FROM sourcing_item si
WHERE si.ID IN item_array
Of course the above doesn't work because MySQL doesn't recognize [] vs. ().
Is there a viable workaround for this issue? I'm surprised they haven't updated MySQL to allow the WHERE IN clause to work with a JSON array...
The MEMBER OF operator does this.
SELECT si.item_name
FROM sourcing_item si
WHERE si.ID MEMBER OF (item_array)

Cakephp 3.x Filter rows on array in multilevel joins

First important structure of my database:
teachers:
id, int
username, varchar
certificates:
id, int
teacher_id, int
vality_date, date
languages:
id, int
certificate_id, int
language_id, int
Teachers hasMany Certificates hasMany Languages
A teacher can have multiple certificates with multiple languages. Multiple languages can get splitted on multiple certificates.
I'm trying to find a cakephp-way to get all teachers, who have a valid certification for defined languages, probably in multiple certifications, but it's hard to build a query in cakephp. I tried so much, but I always get teachers who have all or only one of the requested languages.
How would you solve this problem?
You would do this through joins (or with what the QueryBuilder calls matching().
If you would use:
$teachers = $this->Teachers->find()
->innerJoinWith('Certificates.Languages');
...you would effectively get a table of teachers with for each teacher the certificates and for each certificate the language. There would probably be duplicates as well.
You can now filter on the joined data (and keep out duplicates):
$lang_list = ['NL', 'DE'];
$teachers = $this->Teachers->find()
->where(['Languages.lang IN' => $lang_list])
->innerJoinWith('Certificates.Languages')
->group('Teachers.id');
I am not sure if this would work directly, but it is definitely something like this.
The SQL IN keyword can be used to limit to values of an array. Alternatively you could construct multiple AND statements (for whatever reason).
Also note that I personally prefer a ...JoinWith over matching. (For no real reason.)
For completeness, with matching() it would look like:
$lang_list = ['NL', 'DE'];
$teachers = $this->Teachers->find()
->matching('Certificates.Languages', function ($q) use ($lang_list) {
return $q->where(['lang IN' => $lang_list]);
});
CakepHP - Using innerJoinWith
CakePHP - Filtering by associated data

In clause for a list of pair of conditions

There is a table from where I need to fetch paginated records by applying and condition in a list of paired values, Below is the explanation
Lets say I have a class Billoflading and there are various fields in it
The two important fields in the table are
tenant
billtype
I have a list of pairs which contain values as
[
{`tenant1`, `billtype1`},
{`tenant2`, `billtype2`},
{`tenant3`, `billtype3`},
....
]
I need a JPA query where the fetch will be like
findByTenantAndBilltypeOrTenantAndBillTypeOr.....
in simple sql query it will be like
Select * from `Billoflading` where
`tenant` = 'tenant1' and billtype = 'billtype1'
OR `tenant` = 'tenant2' and billtype = 'billtype2'
OR `tenant` = 'tenant3' and billtype = 'billtype3'
OR ......... so on..
I tried writing a JPA query as follows
Page<Billoflading> findByTenantInAndBillTypeIn(List<String> tenants, List<String> billTypes, Page page);
but this had crossover records as well
i.e it gave records for tenant1 and billtype2, benant2 and billtype 3 so on... which are not needed in the result set
can anyone please solve this and help me finding a simple solution like
Page<Billoflading> findByTenantAndBillTypeIn(Map<String, String> tenantsAndBilltyes, Page page);
I am also ready for the native queries in JPA all I need is there should be no crossovers as this is a very sensitive data
The other workaround I had was fetching the records and applying java 8 filters and that works but the no. of records in a page gets reduced
Section 4.6.9 of the JPA specification makes it clear that this is not supported by JPQL, at least not in the form of an in-clause:
4.6.9 In Expressions
The syntax for the use of the comparison operator [NOT] IN in a conditional expression is as follows:
in_expression ::=
{state_valued_path_expression | type_discriminator} [NOT] IN
{ ( in_item {, in_item}* ) | (subquery) | collection_valued_input_parameter }
in_item ::= literal | single_valued_input_parameter
The state_valued_path_expression must have a string, numeric, date, time, timestamp, or enum value.
The literal and/or input parameter values must be like the same abstract schema type of the state_valued_path_expression in type. (See Section 4.12).
The results of the subquery must be like the same abstract schema type of the state_valued_path_expression in type.
It just doesn't operate on tuples.
Your best bet is probably to create a Specification to construct the combination of AND and OR you require. See this blog article how to create Specifications

SQLAlchemy query to return only n results?

I have been googling and reading through the SQLAlchemy documentation but haven't found what I am looking for.
I am looking for a function in SQLAlchemy that limits the number of results returned by a query to a certain number, for example: 5? Something like first() or all().
for sqlalchemy >= 1.0.13
Use the limit method.
query(Model).filter(something).limit(5).all()
Alternative syntax
query.(Model).filter(something)[:5].all()
If you need it for pagination you can do like this:
query = db.session.query(Table1, Table2, ...).filter(...)
if page_size is not None:
query = query.limit(page_size)
if page is not None:
query = query.offset(page*page_size)
query = query.all()
Or if you query one table and have a model for it you can:
query = (Model.query(...).filter(...))
.paginate(page=start, per_page=size))
Since v1.4, SQLAlchemy core's select function provides a fetch method for RDBMS that support FETCH clauses*. FETCH was defined in the SQL 2008 standard to provide a consistent way to request a partial result, as LIMIT/OFFSET is not standard.
Example:
# As with limit queries, it's usually sensible to order
# the results to ensure results are consistent.
q = select(tbl).order_by(tbl.c.id).fetch(10)
# Offset is supported, but it is inefficient for large resultsets.
q_with_offset = select(tbl).order_by(tbl.c.id).offset(10).fetch(10)
# A suitable where clause may be more efficient
q = (select(tbl)
.where(tbl.c.id > max_id_from_previous_query)
.order_by(tbl.c.id)
.fetch(10)
)
The syntax is supported in the ORM layer since v1.4.38. It is only supported for 2.0-style select on models; the legacy session.query syntax does not support it.
q = select(Model).order_by(Model.id).fetch(10)
* Currently Oracle, PostgreSQL and MSSQL.
In my case it works like
def get_members():
m = Member.query[:30]
return m

How do I create a MySQL query using an array?

I need to take an array and use it for a MySQL query.
I tried looking for methods but all of them seem to be related to PHP arrays and not Ruby.
For example, I have terms = ['genetics', 'elderly', 'health'] and I want to use:
con.query "SELECT col1 FROM data1 WHERE MATCH (col2) AGAINST (terms)"
Is this possible?
You can just join your terms in your against clause:
terms = ['genetics' , 'elderly', 'health']
con.query "SELECT col1 FROM data1 WHERE MATCH col2 AGAINST ('#{terms.join(' ')}')"
Note that using match/against will almost certainly be more performative than using a series of like clauses. See this StackOverflow answer for more information: Which SQL query is better, MATCH AGAINST or LIKE?.
Check out the MySQL documentation for more information on full text searching (including possible operators): http://dev.mysql.com/doc/refman/5.5/en/fulltext-search.html.
I'd highly recommend looking into an ORM, such as Sequel, which makes it very easy to generate the proper query in a DBM independent way.
It allows us to use arrays and hashes conveniently. Here's an example using an array to generate the "where" clause in SQL:
my_posts = posts.where(:category => ['ruby', 'postgres', 'linux'])
# WHERE category IN ('ruby', 'postgres', 'linux')
That particular example is part of the "Filtering Records" section.
In a comment, the OP said:
col2 is text with each row having a paragraph, not just one word.
Then you want a LIKE or regex clause that allows each word to be tested. See the "String search functions" section of "Dataset Filtering " for how Sequel allows you to search inside strings.
The code would be something like:
data1.select(:col1).where(Sequel.like(:col2, terms.map{ |t| "%#{ t }%" } ))
which would generate something like:
SELECT col1 FROM data1 WHERE ((col2 LIKE '%genetics%') OR (col2 LIKE '%elderly%') OR (col2 LIKE '%health%'))