I have this query in LINQ to Entities.
var query = (from s in db.ForumStatsSet
where s.LogDate >= date1 && s.LogDate <= date2
group s by new { s.Topic.topicID, s.Topic.subject, s.Topic.Forum.forumName, s.Topic.datum, s.Topic.Forum.ForumGroup.name, s.Topic.Forum.forumID } into g
orderby g.Count() descending
select new TopicStatsData
{
TopicId = g.Key.topicID,
Count = g.Count(),
Subject = g.Key.subject,
ForumGroupName = g.Key.name,
ForumName = g.Key.forumName,
ForumId = g.Key.forumID
});
I know it is kind of an "Evil" query but it is only used in a admin interface. But the SQL it generated is absolutely horrifying. Have a look at this baby.
exec sp_executesql N'SELECT TOP (50)
[Project6].[C1] AS [C1],
[Project6].[TopicId] AS [TopicId],
[Project6].[C4] AS [C2],
[Project6].[subject] AS [subject],
[Project6].[name] AS [name],
[Project6].[forumName] AS [forumName],
[Project6].[C2] AS [C3]
FROM ( SELECT
[Project5].[TopicId] AS [TopicId],
[Project5].[subject] AS [subject],
[Project5].[forumName] AS [forumName],
[Project5].[name] AS [name],
1 AS [C1],
CAST( [Project5].[forumID] AS int) AS [C2],
[Project5].[C1] AS [C3],
[Project5].[C2] AS [C4]
FROM ( SELECT
[Project4].[TopicId] AS [TopicId],
[Project4].[forumID] AS [forumID],
[Project4].[subject] AS [subject],
[Project4].[forumName] AS [forumName],
[Project4].[name] AS [name],
[Project4].[C1] AS [C1],
(SELECT
COUNT(cast(1 as bit)) AS [A1]
FROM [dbo].[tForumStats] AS [Extent14]
LEFT OUTER JOIN [dbo].[tTopic] AS [Extent15] ON [Extent14].[TopicId] = [Extent15].[topicID]
LEFT OUTER JOIN [dbo].[tForum] AS [Extent16] ON [Extent15].[forumID] = [Extent16].[forumID]
LEFT OUTER JOIN [dbo].[tForum] AS [Extent17] ON [Extent15].[forumID] = [Extent17].[forumID]
LEFT OUTER JOIN [dbo].[tForum] AS [Extent18] ON [Extent15].[forumID] = [Extent18].[forumID]
LEFT OUTER JOIN [dbo].[tForumGroup] AS [Extent19] ON [Extent18].[forumGroupID] = [Extent19].[forumGroupID]
LEFT OUTER JOIN [dbo].[tForum] AS [Extent20] ON [Extent15].[forumID] = [Extent20].[forumID]
LEFT OUTER JOIN [dbo].[tForumGroup] AS [Extent21] ON [Extent20].[forumGroupID] = [Extent21].[forumGroupID]
WHERE ([Extent14].[LogDate] >= #p__linq__25) AND ([Extent14].[LogDate] = #p__linq__25) AND ([Extent6].[LogDate] = #p__linq__25) AND ([Extent1].[LogDate]
I do not as anyone to explain that query but it would be great to get some tips on how to optimze the query so that it just do a simple regular join. Something like this works as fine if I write the SQL myself.
SELECT COUNT(*) AS NumberOfViews, s.topicid AS topicId, t.subject AS TopicSubject, g.[name] AS ForumGroupName, f.forumName AS ForumName
FROM tForumStats s
join tTopic t on s.topicid = t.topicid
join tForum f on f.forumid = t.forumid
JOIN tForumGroup g ON f.forumGroupID = g.forumGroupID
WHERE s.[LogDate] between #date1 AND #date2
group by s.topicid, t.subject, f.Forumname, t.Datum, g.[name]
order by count(*) desc
Btw, i LOVE this site. Amazing design and usability! Hope it works good to get some help to :)
Instead of joining all tables in group by you can join the given tables by yourself.
Can you try this;
from s in db.ForumStatsSet
join t in db.Topics on t.TopicId == s.TopicId
join f in db.Forums on f.ForumId == t.ForumId
join fg in db.ForumGroups on fg.ForumGroupId == f.ForumGroupId
where s.LogDate >= date1 && s.LogDate <=
group s by new { t.TopicId, t.subject, f.forumName, t.datum, fg.name, f.forumID } into g
orderby g.Count() descending
select new TopicStatsData
{
TopicId = g.Key.topicID,
Count = g.Count(),
Subject = g.Key.subject,
ForumGroupName = g.Key.name,
ForumName = g.Key.forumName,
ForumId = g.Key.forumID
});
ps: There may be some errors, but logically it should be correct!
I think the problem is with the grouping construct. Try extract the data first (so there is not need to go via properties), then group by the extracted data.
IOW, try write the LINQ like would for the SQL.
Related
How do I write this in linq:
SELECT
c.customerNumber,
IsNull(l.loanNumber, '') AS loanNumber,
dd.documentTypeName,
dd.documentSubTypeName,
d.filename,
(SELECT propertyId FROM SystemProperties WHERE propertyKey LIKE 'acculoan.inputType.Other') AS inputType
FROM
document AS d INNER JOIN qryDocumentDefinitions AS dd
ON d.documentDefId = dd.documentDefId
AND d.documentId = #DocumentId
INNER JOIN customer AS c
ON c.customerId = d.customerId
LEFT OUTER JOIN loan AS l
ON l.loanId=d.loanId
Help needed with the isnull especially and the nested select.
Many thanks in advance..!
You can try the below (have not been able to test, maybe will require some adjustments, but should be in the same form);
from Doc in db.document
join DocDef in db.qryDocumentDefinitions on doc.documentDefId equals DocDef.documentDefId
join Cus in db.Customer on Cus.customerId = Doc.customerId
from loan in db.loan
.Where(loan => loan.loanId == Doc.loanId).DefaultIfEmpty()
select new
{
CustNo= Cus.customerNumber
,loan == null ? "" : loan.loanNumber
,DocType= DocDef.documentTypeName
,DocSubType= DocDef.documentSubTypeName
,filename = Doc.filename
,inputType = (?int)(from Sys in db.SystemProperties
where Sys.propertyKey.Contains("acculoan.inputType.Other")
}
I am trying to figure out what a query is doing and I just do not understand why it would join its self to its self on multiple occassions highlighted bit is the piece i am talking about?
its the part that starts with the [SupplyStatusUpdated] = COALESCE( gas supply and gas supply history
USE [CRM];
SELECT gs.GasSupplyID,
[Account ID] = acc.AccountID,
[GMSReference] = cast(gms.SiteRefNum as varchar),
[AccountNumber] = cast(gms.AccountNum as varchar),
[Organisation Name] = prf.[Name] ,
con.DeclaredDate,
[Contract Date] = CAST(con.ContractDate AS DATE),
[Contract Version] = cv.Name,
[Contract Status] = cs.Name,
loa.ContractEndDate [LOA CED],
gs.CurrentSupplierEndDate [PrevSupplierEndDate],
loa.ContractEndDate,
con.StartDate,
[Supply Status] = gss.Name,
[SupplyStatusUpdated] = COALESCE(
(
SELECT TOP 1 MAX(gsh2.CreatedDate)
FROM GasSupply gs2
INNER JOIN GasSupplyHistory gsh2
ON gsh2.GasSupplyFK = gs2.GasSupplyID
WHERE gsh2.EventFK = 2
AND gsh2.Notes LIKE '%Gas Supply Status (%'
AND gsh2.GasSupplyFK = gs.GasSupplyID
GROUP BY gsh2.GasSupplyFK
),
(
SELECT TOP 1 MAX(gsh3.CreatedDate)
FROM GasSupplyHistory gsh3
INNER JOIN (
SELECT gsh4.GasSupplyFK, MAX(gsh4.EventFK) AS [MaxEvent]
FROM GasSupplyHistory gsh4
WHERE gsh4.GasSupplyFK = gs.GasSupplyID
GROUP BY gsh4.GasSupplyFK
HAVING MAX(gsh4.EventFK) = 1
) dt
ON dt.GasSupplyFK = gsh3.GasSupplyFK
)
),
[EAC] = gs.EstimatedAnnualConsumption,
[PreviousSupplier] = r.name,
[Branch] = b.name,
[LeadSource] = ls.name,
gs.UnitPrice,
gs.StandingCharge,
gs.WholesalePrice,
COALESCE(deal.weeknumber,DATEPART(ISOWK, con.[ContractDate])) AS [Week]
FROM acc.Account acc
INNER JOIN [Profile] prf
ON acc.ProfileFK = prf.ProfileID
INNER JOIN [Contract] con
ON acc.AccountID = con.AccountFK
INNER JOIN [loacontract] lo
ON lo.ContractFK = con.ContractID
LEFT join [LeadSource] ls
ON ls.LeadSourceID = con.LeadSourceFK
INNER JOIN [ContractStatus] cs
ON cs.ContractStatusID = con.ContractStatusFK
INNER JOIN [ContractVersion] cv
ON cv.ContractVersionID = con.ContractVersionFK
INNER JOIN GasSupply gs
ON gs.ContractFK = con.ContractID
INNER JOIN GasSupplyStatus gss
ON gss.GasSupplyStatusID = gs.GasSupplyStatusFK
LEFT JOIN Deal deal
ON deal.ContractFK = con.ContractID
OUTER APPLY GetGMSReferenceNumbers(con.ContractID) gms
LEFT JOIN Branch b
ON b.BranchID = deal.BranchFK
LEFT JOIN DealBroker bro
ON bro.DealFK = deal.DealID
AND bro.BrokerTypeFK = 36
LEFT JOIN Person p
ON p.PersonID = bro.EmployeeFK
LEFT JOIN Reseller r
ON r.ResellerID = gs.ResellerFK
LEFT JOIN (
SELECT l.contractfk,
MIN(l.contractenddate)[ContractEndDate]
FROM CRM.[contract].LOAContract l
GROUP BY l.ContractFK
) loa
ON loa.ContractFK = con.ContractID
WHERE acc.AccountID not in (
select AccountFK
from AccountOption
where OptionFK=9
)
AND cast(gms.SiteRefNum as varchar) IS NULL
COALESCE(Something, SomethingElse) says if the first argument is NULL, return the second argument (note that you can have more than 2 args and it'll just keep going down the list).
As such it's running the first sub-query, and if the result is NULL, returning the result of the second query. Why exactly is your business logic, which we can't answer :-)
(MSDN link on Coalesce)
COALESCE returns the first non-null value it finds, so if the GasSupply query returns a result it will use that: if that returns null it will see if the GasSupplyHistory query returns a result, and if so use that. If both queries return null then SupplyStatusUpdated will be null.
It joins to itself to get historical records from the same source as where it gets the current record.
Representation of historical data is is one common reason for using a BigData/NoSQL database instead of a SQL/Relational database.
Im having performance issues with this query. If I remove the status column it runs very fast but adding the subquery in the column section delays way too much the query 1.02 min. How can I modify this query so it runs fast getting the desired data.
The reason I put that subquery there its because I needed the status for the latest activity, some activities have null status so I have to ignore them.
Establishments: 6.5k rows -
EstablishmentActivities: 70k rows -
Status: 2 (Active, Inactive)
SELECT DISTINCT
est.id,
est.trackingNumber,
est.NAME AS 'establishment',
actTypes.NAME AS 'activity',
(
SELECT stat3.NAME
FROM SACPAN_EstablishmentActivities eact3
INNER JOIN SACPAN_ActivityTypes at3
ON eact3.activityType_FK = at3.code
INNER JOIN SACPAN_Status stat3
ON stat3.id = at3.status_FK
WHERE eact3.establishment_FK = est.id
AND eact3.rowCreatedDT = (
SELECT MAX(est4.rowCreatedDT)
FROM SACPAN_EstablishmentActivities est4
INNER JOIN SACPAN_ActivityTypes at4
ON est4.establishment_fk = est.id
AND est4.activityType_FK = at4.code
WHERE est4.establishment_fk = est.id
AND at4.status_FK IS NOT NULL
)
AND at3.status_FK IS NOT NULL
) AS 'status',
est.authorizationNumber,
reg.NAME AS 'region',
mun.NAME AS 'municipality',
ISNULL(usr.NAME, '') + ISNULL(+ ' ' + usr.lastName, '')
AS 'created',
ISNULL(usr2.NAME, '') + ISNULL(+ ' ' + usr2.lastName, '')
AS 'updated',
est.rowCreatedDT,
est.rowUpdatedDT,
CASE WHEN est.rowUpdatedDT >= est.rowCreatedDT
THEN est.rowUpdatedDT
ELSE est.rowCreatedDT
END AS 'LatestCreatedOrModified'
FROM SACPAN_Establishments est
INNER JOIN SACPAN_EstablishmentActivities eact
ON est.id = eact.establishment_FK
INNER JOIN SACPAN_ActivityTypes actTypes
ON eact.activityType_FK = actTypes.code
INNER JOIN SACPAN_Regions reg
ON est.region_FK = reg.code --
INNER JOIN SACPAN_Municipalities mun
ON est.municipality_FK = mun.code
INNER JOIN SACPAN_ContactEstablishments ce
ON ce.establishment_FK = est.id
INNER JOIN SACPAN_Contacts con
ON ce.contact_FK = con.id
--JOIN SACPAN_Status stat ON stat.id = actTypes.status_FK
INNER JOIN SACPAN_Users usr
ON usr.id = est.rowCreatedBy_FK
LEFT JOIN SACPAN_Users usr2
ON usr2.id = est.rowUpdatedBy_FK
WHERE (con.ssn = #ssn OR #ssn = '*')
AND eact.rowCreatedDT = (
SELECT MAX(eact2.rowCreatedDT)
FROM SACPAN_EstablishmentActivities eact2
WHERE eact2.establishment_FK = est.id
)
--AND est.id = 6266
ORDER BY 'LatestCreatedOrModified' DESC
Try moving that 'activiy' query to a Left Join and see if it speeds it up.
I solved the problem by creating a temporary table and creating an index to it, this removed the need of the slow subquery in the select statement. Then I join the temp table as I do with normal tables.
Thanks to all.
How would one write this query in linq (VB)
select
g.*
from PROB_GROUP g
inner join
(
select
PGR_NAME,
PGR_PCELL,
max(PGR_VERSION) max_version
from PROB_GROUP
group by PGR_NAME, PGR_PCELL
) grouped_g
on g.PGR_NAME = grouped_g.PGR_NAME
and g.PGR_PCELL = grouped_g.PGR_PCELL
and g.PGR_VERSION = grouped_g.max_version
order by g.PGR_TYPE, g.PGR_NAME
got it
From pp In DB.PROB_GROUPs Join p1 In
(From p In DB.PROB_GROUPs Group By p.PGR_NAME, p.PGR_PCELL Into g = Group Select PGR_NAME, PGR_PCELL, H_VERSION = g.Max(Function(p) p.PGR_VERSION))
On p1.H_VERSION Equals pp.PGR_VERSION And p1.PGR_NAME Equals pp.PGR_NAME And p1.PGR_PCELL Equals pp.PGR_PCELL Select pp Order By pp.PGR_TYPE, pp.PGR_NAME
Should be ok right?
I have a LEFT OUTER OUTER join in LINQ that is combining with the outer join condition and not providing the desired results. It is basically limiting my LEFT side result with this combination. Here is the LINQ and resulting SQL. What I'd like is for "AND ([t2].[EligEnd] = #p0" in the LINQ query to not bew part of the join condition but rather a subquery to filter results BEFORE the join.
Thanks in advance (samples pulled from LINQPad) -
Doug
(from l in Users
join mr in (from mri in vwMETRemotes where met.EligEnd == Convert.ToDateTime("2009-10-31") select mri) on l.Mahcpid equals mr.Mahcpid into lo
from g in lo.DefaultIfEmpty()
orderby l.LastName, l.FirstName
where l.LastName.StartsWith("smith") && l.DeletedDate == null
select g)
Here is the resulting SQL
-- Region Parameters
DECLARE #p0 DateTime = '2009-10-31 00:00:00.000'
DECLARE #p1 NVarChar(6) = 'smith%'
-- EndRegion
SELECT [t2].[test], [t2].[MAHCPID] AS [Mahcpid], [t2].[FirstName], [t2].[LastName], [t2].[Gender], [t2].[Address1], [t2].[Address2], [t2].[City], [t2].[State] AS [State], [t2].[ZipCode], [t2].[Email], [t2].[EligStart], [t2].[EligEnd], [t2].[Dependent], [t2].[DateOfBirth], [t2].[ID], [t2].[MiddleInit], [t2].[Age], [t2].[SSN] AS [Ssn], [t2].[County], [t2].[HomePhone], [t2].[EmpGroupID], [t2].[PopulationIdentifier]
FROM [dbo].[User] AS [t0]
LEFT OUTER JOIN (
SELECT 1 AS [test], [t1].[MAHCPID], [t1].[FirstName], [t1].[LastName], [t1].[Gender], [t1].[Address1], [t1].[Address2], [t1].[City], [t1].[State], [t1].[ZipCode], [t1].[Email], [t1].[EligStart], [t1].[EligEnd], [t1].[Dependent], [t1].[DateOfBirth], [t1].[ID], [t1].[MiddleInit], [t1].[Age], [t1].[SSN], [t1].[County], [t1].[HomePhone], [t1].[EmpGroupID], [t1].[PopulationIdentifier]
FROM [dbo].[vwMETRemote] AS [t1]
) AS [t2] ON ([t0].[MAHCPID] = [t2].[MAHCPID]) AND ([t2].[EligEnd] = #p0)
WHERE ([t0].[LastName] LIKE #p1) AND ([t0].[DeletedDate] IS NULL)
ORDER BY [t0].[LastName], [t0].[FirstName]
I'm not sure if it will change the result set with "AND ([t2].[EligEnd] = #p0" as part of the subquery rather than the join condition. One thing I like to do with complex queries might help you here. I like to break them into smaller queries before combining them. The deferred execution of LINQ lets us do multiple statements with one eventual call to the database. Something like this:
var elig = from mri in vwMETRemotes
where met.EligEnd == Convert.ToDateTime("2009-10-31")
select mri;
var users = from l in Users
where l.LastName.StartsWith("smith")
where l.DeletedDate == null
var result = from l in users
join mr in elig on l.Mahcpid equals mr.Mahcpid into lo
from g in lo.DefaultIfEmpty()
orderby l.LastName, l.FirstName
select g
Breaking it down like that can make it easier to debug, and perhaps it can tell LINQ better what you intend.
Code ended up looking like this. RecodePopulation and RecordRegistration are just methods to translate values from the query.
var elig = from mri in db.MetRemote
where mri.EligEnd == Convert.ToDateTime(ConfigurationManager.AppSettings["EligibilityDate"])
orderby mri.EligEnd
select mri;
var users = from l in db.Users
where l.LastName.StartsWith(filter)
where l.DeletedDate == null
select l;
var results = (from l in users
join m in elig on l.MahcpId equals m.MAHCPID into lo
from g in lo.DefaultIfEmpty()
orderby l.LastName, l.FirstName
select new UserManage()
{
Username = l.Username,
FirstName = l.FirstName,
LastName = l.LastName,
DateOfBirth = l.DOB,
Gender = l.Gender,
Status = RecodePopulation(g.Population, l.CreatedDate),
UserId = l.Id,
WellAwardsRegistered = RecodeRegistration(l.Id, 1)
}).Distinct().OrderBy(a => a.LastName).ThenBy(n => n.FirstName).Skip((currentPage - 1) * resultsPerPage).Take(resultsPerPage);