Linq Query Condition for multiple row - database

I tried to solve one query from last 2 days but didn't.
It looks easy to understand but can't made.
There are two column in Table for example:
ResourceId || MappingId
1 2
1 3
2 2
2 4
3 2
3 4
4 2
4 5
5 2
5 4
This is one table which have two fields ResourceId and MappingId.
Now I want resourceId which have Mappingid {2,4}
Means answer must be ResourceId {2,3,5}
How can I get this answer in Linq Query?

Use Contains of collection. This method can be translated by Entity Framework into SQL IN operator:
int[] mappingIds = { 2, 4 };
var resources = from t in table
where mappingIds.Contains(t.MappingId)
select t.ResourceId;
Lambda syntax:
var resources = table.Where(t => mappingIds.Contains(t.MappingId))
.Select(t => t.ResourceId);
Generated SQL will look like:
SELECT [Extent1].[ResourceId]
FROM [dbo].[TableName] AS [Extent1]
WHERE [Extent1].[MappingId] IN (2,4)
UPDATE: If you want to get resources which have ALL provided mapping ids, then
var resources = from t in table
group t by t.ResourceId into g
where mappingIds.All(id => g.Any(t => t.Id == id))
select g.Key;
Entity Framework is able to translate this query into SQL, but it will not be that beautiful as query above.

IQueryable<int> resourceIds = table
// groups items by ResourceId
.GroupBy(item => item.ResourceId)
// consider only group where: an item has 2 as MappingId value
.Where(group => group.Select(item => item.MappingId).Contains(2))
// AND where: an item has 4 as MappingId value
.Where(group => group.Select(item => item.MappingId).Contains(4))
// select Key (= ResourceId) of filtered groups
.Select(group => group.Key);

Related

Cakephp condition on belongs to many table

I have 3 tables
users
bases
bases_users
In usersTable I have created a belongsToMany relation like
$this->belongsToMany('Bases', [
'foreignKey' => 'user_id',
'targetForeignKey' => 'base_id',
'joinTable' => 'bases_users',
]);
Now I am trying to fetch all users where user is under this login user bases.
Query like below
SELECT users.name FROM users
INNER JOIN bases_users on bases_users.user_id = users.id
WHERE bases_users.base_id in (1,2) //login user 1 has tow bases (1,2)
GROUP BY Users.id
I'm trying to get accepted data using below query with content
$this->Users->find()
->contain([
'UserAuthorities',
'Bases' => function($q) use($userId){
return $q->where(['Bases.users.id' => $userId]);
}
])
How can I match the data where BasesUsers.user_id = $userId ?
I have tried the code after #ndm comment like below
$queryUsers = $this->Users->find()
->contain([
'UserAuthorities',
'Bases'
])
->innerJoinWith('BasesUsers', function(\Cake\ORM\Query $q) {
return $q->where(['BasesUsers.user_id' => 10]);
})
->where($conditions)
->order($order)
;
Query is generating :
SELECT
...
FROM
users Users
INNER JOIN bases_users BasesUsers ON (
BasesUsers.user_id = 10
AND Users.id = BasesUsers.user_id
)
INNER JOIN user_authorities UserAuthorities ON UserAuthorities.id = Users.user_authority_id
WHERE
(
Users.company_id = 1
AND Users.is_deleted = FALSE
)
ORDER BY
Users.created DESC
LIMIT
20 OFFSET 0
Here My expecting query is
INNER JOIN bases_users BasesUsers ON (
BasesUsers.user_id = 10
)
Sample data
Users table :
id, name,
1 A
2 B
3 C
4 D
Bases table :
id Name
1 Base 1
2 Base 2
3 Base 3
BasesUsers:
id user_id base_id
1 1 1
2 1 2
3 2 1
4 3 1
5 4 3
6 3 2
Expected result for user id 1 logged in
name bases
A Base1,Base2
B Base1
C Base1,Base2
How I will remove AND Users.id = BasesUsers.user_id from innerJoin with ?
I have the same problem, not exactly for compare two id's but for check if a column match a condition, i solve this using matching()
Read this of CakePHP documentation:
https://book.cakephp.org/4/en/orm/retrieving-data-and-resultsets.html#filtering-by-associated-data-via-matching-and-joins
I use those examples and work perfect. Hope this can help you.

How can I make search and sort logic between different data in MicroServices?

We have two data tables like item, itemMeta. Each table has CRUD APIs. and each data relations one to one.
<item table in A server>
id name created_at
------------------------
1 a_text 2022-08-23
2 b_text 2022-08-23
3 c_text 2022-08-23
4 d_text 2022-08-23
5 e_text 2022-08-23
...
xxxx hello_text 2022-08-23
...
<itemMeta table in B server>
id itemId price created_at
--------------------------------
1 1 10 2022-08-23
1 11 110 2022-08-23
1 24 420 2022-08-23
1 4 130 2022-08-23
1 5 1340 2022-08-23
....
yyyy xxxx 500 2022-08-23
....
When I want make endpoint like
/search-with-item-meta?search=o_text&page=4&sort=highprice-to-lowprice
I shoud call items with search text and call itemMeta with price sort infomations and then matching two datas with uniq id.
but item table hasn't price and itemMeta table hasn't title and also has pagination. Unfortunately, two table is different DB and seperate place. so It should call with APIs.
simply I will make complete with add field price at item, add field title at itemMeta. But It is not clear. and worried about to sync with two table and pagination.
How can I solve this issues?
We used Postgresql DB with typeorm and NestJS
I am writing this answer based on MySql.
Ensure that you have made the relationship between the entities then Create a queryBuilder and join the two tables in your items repository like below
relationalQuery(){
return itemRepository.createQueryBuilder("items")
.leftJoinAndSelect("items.itemMeta","itemMeta")
}
Now we need a function to pass all parameter to filter them and return paginated response
async findAll(page: number, limit: number, search: string, sort: string, _queryBuilder: SelectQueryBuilder<T>){
queryBuilder = _queryBuilder.take(limit).skip((page - 1) * limit)
if (sort) {
let order = "ASC"
if (sort === "highprice-to-lowprice") {
order = "DESC"
}
queryBuilder.addOrderBy("itemMeta.price", order)
}
if (search) {
queryBuilder.andWhere(new Brackets((qb: SelectQueryBuilder<T>) => {
condition = {
operator: like,
parameters: [`${qb.alias}_name}`, `:${name}`],
}
qb = qb.orWhere(qb['createWhereConditionExpression'](condition), {
name: `%${search}%`
}),
})
})
[items, totalItems] = await queryBuilder.getManyAndCount()
let totalPages = totalItems / limit
if (totalItems % limit) totalPages = Math.ceil(totalPages)
retrun{
items,
totalItems,
totalPages,
}
}
Calling this function
const query = relationalQuery()
findAll(1,15,"o_text","highprice-to-lowprice",query)
This is a demo of how to implement it. You can add a column-wise filter, sort and search.Then you have to pass a object for sort like
sort_by:{
name:"ASC",
id: "DESC",
"itemMeta.price":"DESC"
}
You have to make a customize pagination function like the above where you have to break down all the columns and operations of your own.

SQL - Remove Duplicates

I've inherited data from another provider and have 2 tables to clean up
Rooms
Items
Items are within a Room and are linked via Rooms.RoomID / Items.RoomID
Each time an Item has been inspected it has created a Duplicate of the Room & Item, so I have 6 records for each Room and each Item (Each with a unique RoomID, so 1 to 1)
My aim is to remove the Duplicate Rooms and keep only the latest set of records, then update the Items table with the RoomID (So I have 1 to Many i.e. 1 Room with 6 Item records)
I can GROUP the Rooms and obtain the MAX RoomID but don't know how to do the UPDATE
A kind of suedo would be this:
UPDATE a
SET a.RoomID = MAX(b.RoomID)
FROM [dbo].[tmp_Items] a
inner join [dbo].[tmp_Rooms] b on b.PropertyID = a.PropertyID
and b.FloorLevel = a.FloorLevel
and b.Reference = a.Reference
The combination of PropertyID, FloorLevel, and Reference provides a unique link between Items and Rooms as these columns are in both tables and Reference is unique to each floor of a property (Each Room of each Floor is numbered starting from 1)
Any help or guidance appreciated :)
Use a subquery to aggregate before joining:
UPDATE i
SET i.RoomID = r.max_roomid
FROM [dbo].[tmp_Items] i JOIN
(SELECT PropertyID, FloorLevel, Reference, MAX(r.RoomID) as max_roomid
FROM [dbo].[tmp_Rooms] r
GROUP BY PropertyID, FloorLevel, Reference
) r
ON r.PropertyID = i.PropertyID AND
r.FloorLevel = i.FloorLevel AND
r.Reference = i.Reference;

What is the query for table 3?

I have extracted these two tables from a SQL Database:
query for table 1:
SELECT POM_DOCNO,
POM_DATE,
SUP_CODE,
POM_CREATEDBY
FROM SI_PURORDERMASTER
WHERE POM_YEAR = 2012
AND POM_PERIOD = 6
query for table 2:
SELECT POM_DOCNO,
ITM_ITEMCODE,
ITM_ITEMDESC,
POD_QTY,
POD_RATE
FROM SI_PURORDERDETAIL
WHERE POM_YEAR = 2012
AND POM_PERIOD = 6
query to get table 3 ?
I have tried using joins but always end up with wrong result :/
Is there anyway to get table 3 with just table 1 & 2 ?
Both table 1 and 2 have "POM_DOCNO" column in common.
Try something like that;
SELECT TOP 5
SIR.POM_DOCNO,
SIR.POM_DATE,
SIR.SUP_CODE,
SIL.ITM_ITEMCODE,
SIL.POD_QTY,
SIL.POD_RATE,
SIR.POM_CREATEDBY
FROM SI_PURORDERMASTER SIR inner join SI_PURORDERDETAIL SIL ON SIR.POM_DOCNO = SIL.POM_DOCNO
WHERE SIR.POM_YEAR = 2012
AND SIR.POM_PERIOD = 6
Also, just use TOP to limit results. If you want to specift order you should use order by

SUM and DISTINCT of two different columns

I have a table Employee with say the following records
EmpID Salary Date
10 2000 1/1/2011
10 2000 2/1/2011
20 2000 1/1/2011
I want to count the total number of employees and the total salary (based on some other parameters)
Is there a easy way to write the following SQL query in entity framework.
select Sum(Salary), count(distinct(EmployeeID)) from empdb.employeesalary (where clause)
Have a class into which I need to select these values
class EmployeeEntity
{
decimal TotalAmount;
int EmployeeCount
}
I currently do two queries in EF as follows
objectcontext.employeesalary.Sum(c => c.Salary);
objectcontext.employeesalary.Select(c => c.EmployeeID).Distinct().Count();
How can I merge these into a single statement using Entity Framework. Am I missing something here.
Try something like this:
objectcontext.employeesalary
.Where(c => ...)
.GroupBy(_ => default(string))
.Select(g => new
{
Sum = g.Sum(c => c.Salary),
Count = g.Select(c => c.EmployeeID).Distinct().Count()
});
how about this ? you can merge your result of EF into your Employee Entity Class
var q = from f in objectcontext.employeesalary
where [clause]
group f by f.EmpID into g
select new EmployeeEntity
{
TotalAmount = g.Sum(c => c.Salary),
EmpmloyeeCount = g.Select(c => c.EmployeeID).Discinct().Count()
}
var EmployeeSummary = new List<EmployeeEntity>(q.ToList());

Resources