LINQ intersect? - linq

I have two tables in form of these clases
public class Movie
{
private int MovieID;
private string Title;
}
public class transactions
{
private int TransactionID;
private int MovieID;
}
so first table contains ALL movies 2nd contains movies which are RENTED
How do I select ALL movies that are left in the store , ie not rented and are available. Tried soething like:
var moviesavailable =
(from m in db.Movies
select m.MovieID ).Intersect
(from trans in db.Transactions
select trans.MovieID)
but not working...

First way to do it is go over all movies and for each look if there is no transaction with the same MovieID:
db.Movies.Where(m => !db.Transactions.Any(t => t.MovieID == m.MovieID))
Second way is to make left join. We join all rows from Movies and their equivalent rows from Transactions. If there is no row in Transactions for a row in Movies, then for this row the transaction is null (DefaultIfEmpty):
from m in db.Movies
join t in db.Transactions on m.MovieID equals t.MovieID into g
from t in g.DefaultIfEmpty()
where t == null
select m.MovieID

Related

Inner join with more than one OR conditions in spring boot

I am using spring boot specification and trying to execute a query that looks like this -
SELECT DISTINCT
p.name
FROM
partner p
INNER JOIN
detail d ON p.detail_id = d.id
INNER JOIN
account a ON d.account_id = a.id
OR d.crm_id = a.top_parent
OR d.crm_id = a.global_partner
I have used the code
Join<Partner, Detail> details = root.join("detail");
Join<Detail, Account> account = details.join("account");
Predicate global = cb.equal(details.get("crm_id "), account.get("top_parent"));
Predicate top = cb.equal(details.get("crm_id "), account.get("global_partner"));
account.on(cb.or(global, top));
However, it creates the query
SELECT DISTINCT
p.name
FROM
partner p
INNER JOIN
detail d ON p.detail_id = d.id
INNER JOIN
account a ON d.account_id = a.id
AND (d.crm_id = a.top_parent
OR d.crm_id = a.global_partner)
Notice the AND operator in the query...I need to replace it OR operator
Another use case I am struggling with
#Entity
public class Detail {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#OneToMany(mappedBy = "detail", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Set<Skill> skills;
}
I am trying to generate the query below using specifications
order by (select count(s.detail_id) from skill s where detail.id = s.detail_id AND s.category is not null) desc
I have used the code below
cq.orderBy(cb.desc(cb.size(details.get("skills"))));
But the query it generates is
order by (select count(s.detail_id) from skill s where detail.id = s.detail_id) desc
Notice that I am unable to add an extra AND to the order by clause
I believe you can not change that AND.
could you change the query in the following way
SELECT DISTINCT p.name
FROM partner p INNER JOIN detail d ON p.detail_id = d.id, account a
where d.account_id = a.id
OR d.crm_id = a.top_parent
OR d.crm_id = a.global_partner
and the jpa criteria similar to
Join<Partner, Detail> details = root.join("detail");
Root<Account> account = criteria.from(Account.class);
Predicate global = cb.equal(details.get("crm_id"), account.get("top_parent"));
Predicate top = cb.equal(details.get("crm_id"), account.get("global_partner"));
Predicate byId = cb.equal(details.get("account").get("id"), account.get("id"));
Predicate or = cb.or(global, top, byId);
criteria.where(or);

how to use JPQL query to count values from a table & combine with an other table related data?

I have two tables X and Y. In Table X (Oracle sql), an unique column(primary key) code along other columns in X table.. code column may have some records in table Y which have column code_id. I want to get count of rows in table Y for code with code and other columns in table Y
and I have springboot entity called Entity I want to map results to using jpql so I want the query in JPQL:
public class Entity {
private int id;
private char code;
private String name;
// constructor & setters / getters
}
and Y table have entity Counter
public class Counter {
private int codeid;
}
I want to use jpql query equivalent to this Oracle sql query
select x.*,
(select count(*) from Y y where x.code = y.code_id) as theCount
from X x ORDER BY theCount desc , x.name asc ;
Example:
Code "A" has 3 entries, Code "B" has 2 entries and code "C" has 0 entries in table Y.
code name count
A name1 3
B name2 2
C name3 0
I did some assumptions because I miss your project code. Hope my example will fit your needs. It is not the same SQL but it is still just 1 statement producing the same type of output.
Primary entity Code having collection of Counters:
#Data
#Entity
public class Code {
#Id
private Integer id;
private String code;
private String name;
#OneToMany
#JoinColumn(name = "CODE_ID")
private List<Counter> counterList;
}
#Data
#Entity
public class Counter {
#Id
private Integer id;
}
Spring Data repository:
public interface CodeRepository extends JpaRepository<Code, Integer> {
#Query("select c.code, c.name, count(l) as amount from Code c join c.counterList l group by c.code, c.name")
List<Object[]> getSummary();
}
It returns:
A, TESTNAME1, 3
B, TESTNAME2, 2
In case following is inserted into database:
INSERT INTO CODE (ID, CODE, NAME) VALUES (1, 'A', 'TESTNAME1');
INSERT INTO COUNTER (ID, CODE_ID) VALUES (123,1);
INSERT INTO COUNTER (ID, CODE_ID) VALUES (124,1);
INSERT INTO COUNTER (ID, CODE_ID) VALUES (125,1);
INSERT INTO CODE (ID, CODE, NAME) VALUES (2, 'B', 'TESTNAME2');
INSERT INTO COUNTER (ID, CODE_ID) VALUES (234,2);
INSERT INTO COUNTER (ID, CODE_ID) VALUES (235,2);
This is how the result is produced:
codeRepository.getSummary()
.forEach(sum -> System.out.println(sum[0] + ", " + sum[1] + ", " + sum[2]));

How to write an inner join query to retrieve all records of three tables in Hibernate?

I want to retrieve all records from 3 tables: Personal_Info, Address, and Fitness. I have primary key as CandidateID in Personal_Info table and foreign key as CandidateID in Address table and UserID in Fitness table.
I have written inner query as below which seems to be incorrect as I am not getting all the records from three tables.
public void getAllRecords()
{
int searchId = 1;
Session currentSession = sessionFactory.getCurrentSession();
String query = "FROM Address as a, Fitness as f inner join a.personalInfo as p inner join f.personalInfo as p where p.candidateID=:userID";
Query theQuery = currentSession.createQuery(query);
theQuery.setParameter("userID", searchId);
List<?> list = theQuery.list();
for(int i=0; i<list.size(); i++) {
Object[] row = (Object[]) list.get(i);
System.out.println("Record"+i+": "+row[i]);
}
}
How can I correct this inner query?
You have to join all the three tables using CandidateID.
Try this:
FROM Address as a, Fitness as f, Personal_Info as p
WHERE p.CandidateID = a.CandidateID
AND p.CandidateID = f.UserID

LINQ Select Row with Max date per group

I want to return all the values from my "Categories" table and join that to my "CategorySelections" table to display all the categories and whether the specified user selected them or not.
A complication (which I don't know how to deal with in LINQ) is that the user could have changed his selection/deselection of a particular category over time...each change would have logged in the "CategorySelections" table with a date stamp.
I am after the last selection status.
The following SQL query does what I want:
SELECT cs.UserId, c.CategoryId, m.MaxDate, cs.IsSelected
FROM [myDB].[dbo].[Categories] c
LEFT JOIN [myDB].[dbo].[CategorySelections] cs
ON c.CategoryID = cs.CategoryID AND cs.UserID = 7
INNER JOIN
(
SELECT UserId, CategoryId, Max(CreatedOn) as MaxDate
FROM [myDB].[dbo].[CategorySelections]
GROUP BY UserId, CategoryId
) m
ON cs.UserID = m.UserID AND cs.CategoryID = m.CategoryID AND cs.CreatedOn = m.MaxDate
ORDER BY cs.CategoryI
I need some help getting this done in LINQ.
Below is my attempt, which returns all the selections instead of just the last per category.
var query = from c in db.Category
join cs in db.CategorySelection.Where(x => x.UserID == WebSecurity.CurrentUserId)
on c.CategoryID equals cs.CategoryID into JoinedCategory
from cs in JoinedCategory.DefaultIfEmpty()
select new Selection() { CategoryID = c.CategoryID, CategoryName = c.CategoryName ,IsSelected = cs != null ? cs.IsSelected : false }
I am working in MVC; the "new Selection()" refers to my Model
You may add WHERE statement:
where cs.CreatedOn == CategorySelections.Where(t => t.CategoryId == cs.CategoryId).Max(r => r.CreatedOn)

Linq Nested Inner Joins

I want to join the following Tables
1. B_Book[1st Table]
-B_BID (Book ID)(PK)
-B_Name
-B_CategroyID (FK)
2. BI_BookInstance [2nd Table]
-BI_IID(Instance ID)
-BI_BID (FK)
-BI_Price
3. BC_BookCategory [3rd Table]
-BC_CategoryID (PK)
-BC_CategoryName
First Join B_Book and BI_BookInstance then join the result of those both with BookCategory.
(1st join)[B_BID equals BI_BID]
(2nd nested join)[result of 1st join B_CategoryID equals BC_CategoryID]
Edit
SQL would be something like the following:
SELECT * FROM
(SELECT * FROM B_Book b JOIN BI_BookInstance bi on b.B_BID = bi.BI_BID) as t1
JOIN BC_BookCategoryID bc on bc.BC_CategoryID = t1.B_CategoryID
What matches your query in LINQ would be the following (and you'll notice the similarity with SQL). I've also included some examples on how to rename the fields returned, such as Price or CategoryName:
var results = from b in B_Book
join bi in BI_BookInstance
on b.B_BID equals bi.BI_BID
join bc in BC_BookCategory
on b.B_CategoryID equals bc.BC_CategoryID
select new
{
// put in whatever fields you want returned here:
b.B_BID,
b.B_CategoryID,
b.B_Name,
bi.BI_BID,
bi.BI_IID,
Price = bi.BI_Price,
bc.BC_CategoryID,
CategoryName = bc.BC_CategoryName
};
I have supposed inner joins (your FKs is not null), so i would like query like this:
var ctx = new YourEntities();
var query = from b in ctx.B_Book
from bi in ctx.BI_BookInstance
from bc in ctx.BC_BookCategory
where b.B_BID == bi.BI_BID && b.B_CategoryID == bc.BC_CategoryID
select new
{
BInstID = bi.BI_IID,
BName = b.B_Name,
BPrice = bi.BI_Price,
BCategory = bc.BC_CategoryName
};
foreach (var item in query)
{
Console.WriteLine(item.BInstID);
Console.WriteLine(item.BName);
Console.WriteLine(item.BPrice);
Console.WriteLine(item.BCategory);
Console.WriteLine("");
}
You can do this without explicitly using linq's join statement, provided that navigation properties are in place:
from b in ctx.B_Book
from bi in b.BookInstances
select new { b.Property1, bi.Property2, b.BookCategory.Name }

Resources