How to get multiselect results containing both properties and lists via JPA 2.1 in Java? - jpa

The goal is to get the firstName, lastName, and the list of todos for an employee by using multiselect:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> q = cb.createTupleQuery();
Root emp = q.from(Employee.class);
q.multiselect(
emp.get("firstName").alias("fname"),
emp.get("lastName").alias("lname"),
emp.get("toDoList").alias("toDoList")
).where(cb.equal(emp.get("id"), 12345));
List<Tuple> tuples = em.createQuery(q).getResultList();
Iterator<Tuple> iter = tuples.iterator();
while(iter.hasNext()){
Tuple t = iter.next();
//t.get("fName"); // returns String
//t.get("lName"); // returns String
//t.get("toDoList"); // returns String
//?????
//...
}
The toDoList is just a simple list of Strings. Let's assume employee 12345 has 4 todos. This means I get the following result set:
---------------------------------
| firstName | lastName | toDo |
---------------------------------
| John | Doe | sleep |
---------------------------------
| John | Doe | eat |
---------------------------------
| John | Doe | play |
---------------------------------
| John | Doe | laugh |
---------------------------------
Now I'm looking for a smart way of creating an instance of ONE Employee and setting its firstName, lastName, and toDoList ONCE:
Employee employee = new Employee();
employee.setFirstName(...);
employee.setLastName(...);
employee.setToDoList(...);
What would be the best approach? Thing would get even more complicated if I would add additional relationships (i.e. favoriteSongs).

Unfortunately, you would have to write code for every combination of your multiselect call to get the data from the tuples list, and that code can be very dirty.
There are major disadvantages getting relationships with one query:
the java code for reading the data will get very dirty
One query sound like good performance at first, but this will retrieve duplicate data for every fetched row
So I actually believe that executing separate queries to get the data is a better approach in many cases (like in my case). In other words, I will avoid messy code and use single selects instead. The resulting code for getting the projection's data is much better to maintain and much more readable. Here are some important links I found:
SQL for JPQL with join fetch
SQL for JPQL with join fetch
A user may want every relationship loaded, but join fetching every
relationship, in particular every ToMany relationships will lead to a
huge join (outer joins at that), fetching a huge amount of duplicate
data.
Fetch Join in JPQL
2. Fetch Join in JPQL
And the main disadvantage is that we need to write additional code
which executes the query. But it gets even worse, if the entity has
multiple relations and we need to initialize different relations for
different use cases. In this case we need to write a query for every
required combination of fetch joined relations. This can become quite
messy.

Related

Is there a better way to return a table that has a one-to-many relationship

I am wanting to have my data in a better format so my front-end application can be more efficient if possible. Currently, I am using Postgres and I have a table that contains a one-to-many relationship and after I join my tables, I get multiple rows with mainly repeated data just to show the different 'many' values it has (obviously). Is there any possible way to make it so the 'many' values are put into an array so I don't get so many extra rows or if not, what would be the most efficient way to process the data returned from a one-to-many relationship in the front-end?
Example:
"name" | "attributes"
"Shirt" | "Medium"
"Shirt" | "Red"
Would it be possible to instead get a result like this so that it is easier to process on the front-end:
"name" | "attributes"
"Shirt" | ["Medium", "Red"]
You are looking for the Aggregate Functions array_agg or string_agg.
select name, array_agg(attribute) attributes
from example
group by name;
See demo

How to create a join query between two entities in FIWARE orion?

I have two entites A (postings) and B (users) with a many to one relationship and I want to do an SQL like join to list posts and users together.
I tried the following query, but it only returns an empty array.
I could not find any other documentation regarding this, all tutorials only refer to one id.
https://{{orion}}/v2/entities?q=Post.createdBy==User.id&options=count,keyValues&limit=100
I also tried this variant, but the same result:
https://{{orion}}/v2/entities?q=createdBy==id&options=count,keyValues&limit=100
And I checked that there is at least one entity which matches I manually checked
https://{{orion}}/v2/entities?q=createdBy==urn:ngsi-ld:User:78bc5cac26d1b3abe27cb2cf94b1015a3710958f
This query above returns an entity.
| Post | | User |
|------------------| |--------------|
| ID | | ID |
| Type | | Type |
| Message | | Username |
| CreatedBy: UserId|
In orion the datatype:
"createdBy": {
"type": "Relationship",
"value": "urn:ngsi-ld:User:78bc5cac26d1b3abe27cb2cf94b1015a3710958f",
"metadata": {}
},
The short answer is that you cannot do that kind of join operations using the NGSI API provided by Orion.
The NGSI API is oriented to context management, that is, retrieving and updating context information in the form of entities and their attributes. It is not designed to be a SQL-style language, which would involve a lot of complexity. Orion is a context broker, not a relational database ;)
Fortunately, that kind of join operations can be done by the client, doing several queries to Orion.

Filter postgresql query if multiple rows exist

right now I have the following table:
students | classes |
-------------------------------------
Ally | Math |
Ally | English |
Ally | Science |
Kim | Math |
Kim | English |
I am currently building an advanced search feature where you can search by class and return students who have those classes. I would like to build a query that will return student's that have Math and English and Science in the classes column, so in the case above it would only return the rows that have Ally in them, since she meets the three classes criteria.
If anyone has any advice I would greatly appriciate it, thank you.
I've renamed your tables and such slightly, but partly cause I'm lazy. Here's what I came up with:
select student from studentclasses where
class in ('Math', 'English', 'Science')
group by student
having count(*) = 3;
See the db-fiddle
The idea is to grab all the student-class rows that match what your search is (basically an OR) and group it by the student so that we can limit by the having clause. We could use >= here, but if count for a particular student gets more than 3, we screwed up the IN :) If there are fewer than 3, then we're missing one class, so not all classes were found for that student.
The only caveats are:
I'm assuming you're using a student ID rather than just first name, and that the first name bit is just to make it easier for us to read, otherwise duplicates will abound.
There are no duplicates of a given class for a particular student. That is, if Kim is in Science twice, then that comes up with 3. In that case, you'll need to use a DISTINCT in there somewhere.

Structuring a database

In my database I need the following relations:
Tournament
Tournament Participant (Tpart)
relates a User to a tournament
Round
This is a single match
Hole
relates a Tpart to a round
also holds a score
This is my current Persistent Entities:
Tournament
name Text
urlName Text
location GolfCourseId
startDate Day
endDate Day Maybe
UniqueTName name
UniqueTUrlName urlName
Tpart
tournament TournamentId
userId UserId
deriving Show
deriving Eq
Round
tourn TournamentId
name Text
UniqueRound tourn name
deriving Show
Hole
round RoundId
part TpartId
score Int
deriving Show
I don't know if this is the best structure given the kind of queries I need to do.
I need to
Get the total score for a round for each Tpart
This would be done by summing up the score of all Holes related to a specific round and Tpart
Part | round 1 | round 2 | ...
p1 | 56 | 54
p2 | 60 | 57
Get all the holes and tparts that relate to a round
Part | hole 1 | hole 2| ...
p1 | 3 | 5
p2 | 5 | 6
To get the data on the first table it would require summing all the hole scores for each user. Is this an efficient method? Or would it be better to have another entity RndScore, like this:
RndScore
rnd RoundId
tpart TpartId
score Int
This entity could be updated every time a hole entity is updated. Either of those solutions seem rather robust though.
My advice is: You should always start with a clean, normalized logical relational database design without storing redundant data, and trust that the DBMS will derive your data (i.e., answer your queries) well enough. That is what a DBMS is there for. The next step should be to optimize your physical database design, e.g., choose your indexes, your table storage parameters, etc. Depending on your database, your can even materialize your views, so that their results are stored physically etc. Actually adding derived values in your logical database design (such as your your RndScore relation) should be the last resort, as you will have to ensure their consistency manually.
In general, you should avoid pre-mature optimizations: Ensure that you actually need to optimize your database layout (e.g., by measuring runtimes, checking query execution plans, making estimations about the number of queries you will have to answer, etc.)

sqlite3 select from multiple tables 'where' stuff

I'm trying to query multiple tables at once. Say I have a table named PRESCHOOLERS and I have another one called FAVORITE_GOOEY_TREATS, with a foreign key column in the PRESCHOOLERS table referencing the id field of FAVORITE GOOEY TREAT. What would I do if I wanted to get a list of preschoolers with their first names alongside their favorite treats. I mean something like:
first_name | treat
john | fudge
sally | ice-cream
Here's what I'm trying, but I've got a syntax error on the where part.
SELECT PRESCHOOLERS.first_name, FAVORITE_GOOEY_TREATS.name as treat
FROM PRESCHOOLERS, FAVORITE_GOOEY_TREATS
WHERE PRESCHOOLERS.favorite_treat = FAVORITE_GOOEY_TREATS.id and PRESCHOOLERS.age>15;
As far as I know this kind of thing is alright by sql standards, but sqlite3 doesn't much like it. Can someone point me at some examples of similar queries that work?
Try
SELECT PRESCHOOLERS.first_name, FAVORITE_GOOEY_TREATS.name as treat
FROM PRESCHOOLERS
JOIN FAVORITE_GOOEY_TREATS ON PRESCHOOLERS.favorite_treat = FAVORITE_GOOEY_TREATS.id
WHERE PRESCHOOLERS.age > 15;