linq subquery join and group by - entity-framework

Hi is it possible to translate the below queries into linq ? ...
I am using entity frameworks core and tried to use the stored procedure but it seems like i have to create a model that applies to the metadata of the stored procedure. So i am trying to understand whether this kinda such query can be translated into linq so i don't have to create a separate db model.
SELECT
Stock.stockID ProductID,
stockName ProductName,
categoryName ProductCategory,
typeName ProductType,
sizeName ProductSize,
currentQuantity CurrentQuantity,
standardQuantity QuantityPerBox,
CONVERT(VARCHAR(255),CONVERT(INT,Stock.price)) AvgUnitCost,
CONVERT(VARCHAR(255),CONVERT(INT,x.lastUnitCost)) LastOrderUnitCost,
CONVERT(VARCHAR(10),CONVERT(DATE,x.lastOrderDate)) LastOrderDate
FROM dbo.Stock
LEFT JOIN
(
SELECT stockID,unitPrice lastUnitCost ,orderDate lastOrderDate, ROW_NUMBER() OVER (PARTITION BY stockID ORDER BY orderDate DESC) rn FROM dbo.SalesOrder
JOIN dbo.SalesOrderDetail ON SalesOrderDetail.salesOrderID = SalesOrder.salesOrderID
WHERE customerID = #customerID AND salesStatus = 'S'
) x ON x.stockID = Stock.stockID AND rn = 1
LEFT JOIN dbo.StockCategory ON StockCategory.stockCategoryID = Stock.stockCategoryID
LEFT JOIN dbo.StockType ON StockType.stockTypeID = Stock.stockTypeID
LEFT JOIN dbo.StockSize ON StockSize.stockSizeID = Stock.stockSizeID
WHERE disStock = 0

Almost everything is possible. you just need to be careful with performance.
var query =
from stock in db.Stocks
join x in (
from grp in (
from so in db.SalesOrders
join sod in db.SalesOrderDetails on so.SalesOrderId equals sod.SalesOrderId
where so.CustomerId == customerId && so.SalesStatus == "S"
orderby so.OrderDate descending
select new {
sod.StockId,
LastUnitCost = sod.UnitPrice,
LastOrderDate = so.OrderDate
} into inner
group inner by inner.StockId)
select grp.Take(1)) on x.StockId equals stock.StockId into lastStockSales
from x in lastStockSales.DefaultIfEmpty()
join sc in db.StockCategories on stock.StockCatergotyId equals sc.StockCategoryId into scLeft
from sc in scLeft.DefaultIfEmpty()
join st in db.StockTypes on stock.StockTypeId equals st.StockTypeId into stLeft
from st in stLeft.DefaultIfEmpty()
join ss in db.StockSizes on stock.StockSizeId equals ss.StockSizeId into ssLeft
from ss in ssLeft.DefaultIfEmpty()
where stock.DisStock == 0
select new MyDTO {
ProductId = stock.StockId,
ProductName = stock.StockName,
ProductType = st.TypeName,
ProductSize = ss.SizeName,
CurrentQuantity = stock.CurrentQuantity,
QuantityPerBox = stock.StandardQuantity,
AvgUnitCost = stock.Price,
LastOrderUnitCost = x.LastUnitCost,
LastOrderDate = x.LastOrderDate
};
As you can see is easy to rewrite these queries, I had to change a little bit the logic on how to get the latest sales for a stock item since ROW_NUMBER() OVER (PARTITION... is not supported from a LINQ perspective. Again, you would have to consider performance when rewriting queries.
Hope this helps.

Related

How can I use value from main select in Left Outer Join select - T-SQL

In my below T-SQL Query I need to use EFP_MessageCenter.MessageSender from my main SELECT in the SELECT in my LEFT OUTER JOIN as the value where I have placed <MessageSenderInitials>.
When I set (EFP_MessageCenter_1.MessageSender = EFP_MessageCenter.MessageSender) or (EFP_MessageCenter_1.MessageSender = MessageSenderInitials) I get the error The multi-part identifier "EFP_MessageCenter.MessageSender" could not be bound.
How can I get this to work?
SELECT LOWER(EFP_MessageCenter.MessageSender) AS MessageSenderInitials
, MAX(SenderInfo.FullName) AS SenderFullName
, MAX(SenderInfo.ProfilePicture) AS SenderProfilePicture
, MAX(EFP_MessageCenter_Receiver.UserID) AS ReceiverID
, MAX(EFP_MessageCenter.MessageTimestamp) AS ChangeDate
, COUNT(DisplayCountSelect.Displayed) AS CountNonReadMessages
FROM EFP_MessageCenter_Receiver
INNER JOIN EFP_MessageCenter ON EFP_MessageCenter_Receiver.MessageID = EFP_MessageCenter.id
INNER JOIN EFP_EmploymentUser AS SenderInfo ON EFP_MessageCenter.MessageSender = SenderInfo.Initials
LEFT OUTER JOIN
(SELECT EFP_MessageCenter_Receiver_1.Displayed, EFP_MessageCenter_Receiver_1.UserID, EFP_MessageCenter_1.MessageSender
FROM EFP_MessageCenter AS EFP_MessageCenter_1
INNER JOIN EFP_MessageCenter_Receiver AS EFP_MessageCenter_Receiver_1 ON EFP_MessageCenter_1.id = EFP_MessageCenter_Receiver_1.MessageID
WHERE (EFP_MessageCenter_Receiver_1.Displayed = 0) AND (EFP_MessageCenter_Receiver_1.UserID = 65) AND (EFP_MessageCenter_1.MessageSender = '<MessageSenderInitials>'))
AS DisplayCountSelect
ON DisplayCountSelect.UserID = EFP_MessageCenter_Receiver.UserID
WHERE (EFP_MessageCenter_Receiver.UserID = 65) AND (EFP_MessageCenter.MessageType = 'SPECIFIC')
GROUP BY EFP_MessageCenter.MessageSender
ORDER BY ChangeDate DESC
I've made a slight refactor of your query and changed the outer join to an an outer apply
It's not going to be 100% working I'm sure but should allow you to tweak it and include the correlation you need to.
I suspect you could move the CountNonReadMessages to a count(*) in the apply and possibly remove the aggregation, but that's just a guess.
select Lower(mc.MessageSender) as MessageSenderInitials
, Max(s.FullName) as SenderFullName
, Max(s.ProfilePicture) as SenderProfilePicture
, Max(mr.UserID) as ReceiverID
, Max(mc.MessageTimestamp) as ChangeDate
, Count(s.Displayed) as CountNonReadMessages
from EFP_MessageCenter_Receiver mr
join EFP_MessageCenter mc on mr.MessageID = mc.id
join EFP_EmploymentUser eu on mc.MessageSender = eu.Initials
outer apply (
select mr.Displayed
from EFP_MessageCenter mcx
join EFP_MessageCenter_Receiver mrx on mcx.id = mrx.MessageID
where mrx.Displayed = 0
and mrx.UserId=mr.UserId
and mcx.UserID = 65 /* this should probably be correlated */
and mcx.MessageSender = '<MessageSenderInitials>'
) s
where mr.UserID = 65 and mc.MessageType = 'SPECIFIC'
group by mc.MessageSender
order by ChangeDate desc

How to insert data with select query in postgresql?

How to insert data with select query sum? I tried. The result is affected success > Affected rows: 1. but row no add in the table.
CREATE TABLE Clases(Segment1_ID char(4), Segment1_Name varchar(75), CompanyID char(4), amount Float(53));
INSERT INTO Clases (Segment1_ID, Segment1_Name, CompanyID, amount)
select Segment1_ID, Segment1_Name, dataupload1h_companyid CompanyID, sum(case when Segment3_Formula = '+' then dataupload1d_amount else dataupload1d_amount * -1 end) Amount
from t_dataupload1_header
inner join t_dataupload1_detail
on dataupload1h_id = dataupload1d_id
inner join M_Account
on dataupload1d_accountid = Account_ID
and dataupload1h_companyid = Account_CompanyID
inner join M_Segment4
on Account_Segment4ID = Segment4_ID
and dataupload1h_companyid = Segment4_CompanyID
inner join M_Segment3
on Segment4_Segment3ID = Segment3_ID
and dataupload1h_companyid = Segment3_CompanyID
inner join M_Segment2
on Segment3_Segment2ID = Segment2_ID
and dataupload1h_companyid = Segment2_CompanyID
inner join M_Segment1
on Segment2_Segment1ID = Segment1_ID
and dataupload1h_companyid = Segment1_CompanyID
where dataupload1h_companyid = '1000'
group by Segment1_ID, Segment1_Name, dataupload1h_companyid
order by Segment1_ID, Segment1_Name, dataupload1h_companyid;
Please help. Thank you
If the select is returning the desired results then check whether Auto-commit is turned on in PgAdmin(I suppose you are using this) Or put COMMIT; after the insert.

Postgres get rows which hasnt match in other table

I need your help. I need an advanced Query to my database. Im showing part of my database following:
Place (id, name, address)
Local (id, place_id, name)
PlaceReservation(id, local_id, date)
Media_Place (id, place_id, type)
Now I need a query, which gets all places with logo, which have AT LEAST ONE local which hasn't been reserved on a specific day e.g: 2015-07-01.
Help me please, because I haven't an idea how to do it. I thought about an outer join but I don't know how use it.
I was trying by:
$query = 'SELECT DISTINC *,
(SELECT sum(po.rating)/count(po.id)
FROM "Place_Opinion" po
WHERE po.place_id = p.id AND po.deleted = false) AS rating,
mp.path as logo_path
FROM "Place" p
INNER JOIN "Media_Place" mp ON mp.place_id = p.id
JOIN Local ON Local.place_id = Place.id
LEFT JOIN (
SELECT id AS rr, local_id
FROM PlaceReservation
WHERE date_start = \'2015-07-01\') Reserved ON Reserved.local_id = Local.id
WHERE mp.type = ' . Model_Row_MediaPlace::LOGO_TYPE . '
AND mp.deleted = false
AND p.deleted = false
AND rr IS NULL';
Looking for things that do not exist in a database is usually very inefficient. But you can change the logic around by finding places that do have a booking for the specified date, then LEFT JOIN that to all places with a logo and filter out the records with a reservation:
SELECT DISTINCT p.*, po.rating, mp.path as logo_path
FROM "Place" p
JOIN "Media_Place" mp ON mp.place_id = p.id AND mp.deleted = false AND mp.type = ?
JOIN Local ON Local.place_id = p.id
LEFT JOIN (
SELECT id AS rr, local_id
FROM PlaceReservation
WHERE date_start = '2015-07-01') reserved ON reserved.local_id = Local.id
LEFT JOIN (
SELECT place_id, avg(rating) AS rating
FROM "Place_Opinion"
WHERE deleted = false
GROUP BY place_id) po ON po.place_id = p.id
WHERE p.deleted = false
AND reserved.rr IS NULL;
The average rating per places is calculated in a separate sub-query. The error you had was because you referenced the "Place" table (p.id) before it was defined. For simple columns you can do that, but for sub-queries you can't.

TSQL efficiency - INNER JOIN replaced by EXISTS

Can the following be rewritten to be more efficient?
I would use EXISTS if I didn't need fields from country but I do need those fields, and am not sure how to write this to make it more efficient.
SELECT distinct
p.ProvinceID,
p.Abbv as RegionCode,
p.name as RegionName,
cn.Code as CountryCode,
cn.Name as CountryName
FROM dbo.provinces AS p
INNER JOIN dbo.Countries AS cn ON p.CountryID = cn.CountryID
INNER JOIN dbo.Cities c on c.ProvinceID = p.ProvinceID
INNER JOIN dbo.Listings AS l ON l.CityID = c.CityID
WHERE l.IsActive = 1 AND l.IsApproved = 1
There are two things to note:
You're joining to dbo.Listings which results in many records, so you need to use DISTINCT (usually an expensive operator)
For any tables with columns not in the select you can move into an EXISTS (but the query planner effectively does this for you anyway)
So try this:
SELECT
p.ProvinceID,
p.Abbv as RegionCode,
p.name as RegionName,
cn.Code as CountryCode,
cn.Name as CountryName
FROM dbo.provinces AS p
INNER JOIN
dbo.Countries AS cn
ON p.CountryID = cn.CountryID
WHERE EXISTS (SELECT 1 FROM
dbo.Listings l
INNER JOIN dbo.Cities c
on l.CityID = c.CityID
WHERE c.ProvinceID = p.ProvinceID
AND l.IsActive = 1 AND l.IsApproved = 1
)
Check the query plans before and after - the query planner might be smart enough to do this anyway, but you have removed your distinct
The following will often perform even better by providing the optimizer more useful information:
SELECT
p.ProvinceID,
p.Abbv as RegionCode,
p.name as RegionName,
cn.Code as CountryCode,
cn.Name as CountryName
FROM dbo.provinces AS p
INNER JOIN
dbo.Countries AS cn
ON p.CountryID = cn.CountryID
INNER JOIN (
SELECT
p.ProvinceID
FROM
dbo.Listings l
INNER JOIN dbo.Cities c
on l.CityID = c.CityID
WHERE l.IsActive = 1 AND l.IsApproved = 1
GROUP BY
p.ProvinceID
) list
on list.ProvinceID = p.ProvinceID

Grades of each quiz in Moodle

I'm trying to get grades of each question, I have a query but it only return final grade of whole exam, but i want grade of each question, how to get it?
Here is query that i have:
SELECT mdl_grade_items.id AS ItemID,
mdl_course.shortname AS CourseShortname,
mdl_grade_items.itemname AS ItemName,
mdl_grade_items.grademax AS ItemGradeMax,
mdl_grade_items.aggregationcoef AS ItemAggregation,
mdl_grade_grades.finalgrade AS FinalGrade,
mdl_user.username AS StudentID,
mdl_user.id
FROM mdl_grade_items
INNER JOIN mdl_grade_grades
ON mdl_grade_items.id = mdl_grade_grades.itemid
INNER JOIN mdl_role_assignments
ON mdl_grade_grades.userid = mdl_role_assignments.userid
AND mdl_grade_items.courseid = mdl_role_assignments.mdlcourseid
INNER JOIN mdl_course
ON mdl_course.id = mdl_grade_items.courseid
INNER JOIN mdl_user
ON mdl_user.id = mdl_role_assignments.userid
Ok, i found it
SELECT mqa.id,meqi.grade * (select fraction from mdl_question_attempt_steps where
questionattemptid = mqas.questionattemptid and state like 'mangr%' order by id desc limit
1 ) finalgrade,me.course , mqas.userid,u.firstname, u.lastname, mqa.questionsummary,
mqa.responsesummary , meqi.grade
FROM mdl_question_attempts mqa
left JOIN mdl_question_attempt_steps mqas ON mqa.id = mqas.questionattemptid
left JOIN mdl_user u ON mqas.userid = u.id
left JOIN mdl_examm_question_instances meqi ON meqi.question = mqa.questionid
left JOIN mdl_examm me ON meqi.examm = me.id
WHERE me.course= $courseID and userid = $userID