SQL "WHERE IN" query conversion to LINQ - entity-framework

I'm trying to find a way to convert this very complex SQL Query into LINQ and I can't seem to tackle all the embedded "WHERE IN" clauses. Would someone be so kind as to lend me a helping hand?
Here is the SQL code (don't worry about the stored procedure, it's a count of a row total)
SELECT
(SELECT pac.Name FROM Account pac WHERE pac.AccountID = AC.ParentAccountID) AS ParentAccountName,
ac.Name, dv.DeviceID, dv.Manufacturer, dv.Model, dv.SerialNr, dv.PrinterIPAddress,
(SELECT TOP 1 au.AuditDate FROM PrinterAudit pa WITH (NOLOCK) INNER JOIN Audit au ON au.AuditID = pa.AuditID
WHERE pa.DeviceID=dv.DeviceID
ORDER BY AuditDate DESC) AS AuditDate,
dbo.Get_TotalPageCountByDeviceId( DATEADD(month, -3, GETDATE()), GETDATE(), dv.DeviceID ) as TotalUsageLast3Months
FROM Account ac WITH (NOLOCK)
INNER JOIN Device dv ON ac.AccountID = dv.AccountID
WHERE dv.AccountID IN
( SELECT au.AccountID FROM Audit au WHERE au.AuditDate >= DATEADD(month, -3, GETDATE()) )
AND (dv.Manufacturer + dv.Model) IN
(SELECT (dv2.Manufacturer + dv2.Model)
FROM Device dv2
WHERE dv2.AccountID = dv.AccountID
AND dv2.Manufacturer = dv.Manufacturer
AND dv2.Model = dv.Model
AND (dv2.ERPEquipID IS NOT NULL OR dv2.ERPData IS NOT NULL ) )
AND dv.ERPEquipID IS NULL AND dv.ERPData IS NULL
AND dv.DeviceID IN
(SELECT pa.DeviceID
FROM PrinterAudit pa WITH (NOLOCK)
INNER JOIN Audit au ON au.AuditID = pa.AuditID
WHERE au.AuditDate >= DATEADD(month, -3, GETDATE()))
ORDER BY ParentAccountName, ac.Name
Final Result:
var result =
(from dv in Device
where Audit.Any(au => au.AuditDate >= DateTime.Now.AddMonths(-3)
&& au.AccountID == dv.AccountID)
where Device.Any(dv2 => dv2.AccountID == dv.AccountID
&& dv2.Manufacturer == dv.Manufacturer
&& dv2.Model == dv.Model
&& (dv2.ERPEquipID != null || dv2.ERPData != null)
&& dv.ERPEquipID == null
&& dv.ERPData == null
&& PrinterAudit.Any(pa => pa.Audit.AuditDate >= DateTime.Now.AddMonths(-3) && pa.DeviceID == dv.DeviceID))
orderby dv.Account.ParentAccountID, dv.Account.Name
select new
{
ParentAccountName = Account.Where(pac => pac.AccountID == dv.Account.ParentAccountID).Select(pac => pac.Name),
Name = dv.Account.Name,
DeviceID = dv.DeviceID,
Manufacturer = dv.Manufacturer,
Model = dv.Model,
SerialNumber = dv.SerialNr,
PrinterIPAddress = dv.PrinterIPAddress,
AuditDate = (from pa in PrinterAudit where pa.DeviceID == dv.DeviceID orderby pa.Audit.AuditDate descending select pa.Audit.AuditDate).Take(1),
TotalUsageLast3Months = (from p in PrinterAudit
where p.DeviceID == dv.DeviceID
group p by p.DeviceID into total
select new
{
Total = Get_TotalPageCountByDeviceId(DateTime.Now.AddMonths(-3), DateTime.Now, dv.DeviceID)
})
});

You convert the SQL IN statement to linq with either Contains or Any
Contains
from dv in db.Device
where
(from au in db.Audit
where au.AuditDate >= DateTime.Now.AddMonths(-3)
select au.AccountID).Contains(dv.AccountID)
Any
from dv in db.Device
where
db.Audit.Any(au => au.AuditDate >= DateTime.Now.AddMonths(-3) &&
au.AccountID == dv.AccountID)

Related

Optimizing PgSQL Query function performance

I really need advice on the below, trying to use DB function getpreviousorders..
SELECT o1.* FROM "sample"."order" o1 JOIN "sample".patient p1 ON o1.patient_id = p1.id
WHERE o1.sample_id != _sampleId AND p1.mrn = _mrn
AND ((o1.collection_date is not null AND o1.collection_date >= _createdDate)
OR (o1.collection_date is null AND o1.receipt_date is not null
AND o1.receipt_date >= _createdDate))
UNION
(SELECT o2.* FROM "sample"."order" o2 JOIN "sample".patient p2 ON o2.patient_id = p2.id
WHERE (o2.status = 1 or o2.status = 2 OR o2.status = 3) AND o2.sample_id != _sampleId
AND p2.mrn = _mrn
AND ((o2.collection_date is not null AND o2.collection_date < _createdDate)
OR (o2.collection_date is null AND o2.receipt_date is not null
AND o2.receipt_date < _createdDate)) ORDER by created_date DESC LIMIT 1)
ORDER by collection_date DESC, receipt_date DESC, created_date DESC;
Total time to get 199 previous order is 2628ms, and all most time taken for funciton findPreviousOrders: 2535ms
Analyze Query & Code Snippets !!!

How do you use aggregate functions in LINQ?

I can do this really easily in SQL but I can't translate it into LINQ.
The SQL:
SELECT EmployeeId
,YEAR(DistributionDate) AS DistributionYear
,SUM(SalesLocal * FX.ExchangeRate) AS TotalDistributions
FROM Distributions AS DD INNER JOIN FiscalPeriod AS FP ON DD.DistributionDate BETWEEN FP.StartDate AND FP.EndDate
INNER JOIN FXRates AS FX ON FP.FiscalPeriodId = FX.FiscalPeriodId AND FX.FromCurrencyId = DD.CurrencyId AND FX.ToCurrencyId = 'USD'
GROUP BY EmployeeId, YEAR(DistributionDate)
ORDER BY EmployeeId, DistributionYear
This is my broken attempt at translation:
var pointList = (from dd in db.Distributions
join e in db.Employee on dd.EmployeeId equals e.EmployeeId
join fp in db.FiscalPeriod.Where(p => dd.DistributionDate >= p.StartDate && dd.DistributionDate <= p.EndDate)
join fx in db.Fxrates on (fp.FiscalPeriodId equals fx.FiscalPeriodId) && (fx.FromCurrencyId equals dd.CurrencyId) && (fx.ToCurrencyId equals "USD")
group by dd.EmployeeId && dd.DistributionDate.Year
select new Point<int, decimal?>
{
X = dd.DistributionDate.Year,
Y = dd.Sum(dd.SalesLocal * fx.ExchangeRate)
}).ToList();
Visual Studio complains first that dd is not declared and then really complains once it reaches the join to Fxrates.
I think this may be close to what you want:
var pointList = (from dd in db.Distributions
join e in db.Employee on dd.EmployeeId equals e.EmployeeId
from fp in db.FiscalPeriod.Where(p => dd.DistributionDate >= p.StartDate && dd.DistributionDate <= p.EndDate)
from fx in db.Fxrates.Where(fx2 => fp.FiscalPeriodId == fx2.FiscalPeriodId && fx2.FromCurrencyId == dd.CurrencyId && fx2.ToCurrencyId == "USD")
group new { dd, fx } by new { dd.EmployeeId, dd.DistributionDate.Year } into distGroup
select new
{
X = distGroup.Key.Year,
Y = distGroup.Sum(d => d.dd.SalesLocal * d.fx.ExchangeRate)
}).ToList();

Select SQL case when for Entity Framework

I have this select which works in T-SQL, but need to convert to Entity Framework. How can I use case in Entity Framework?
select
*
from
Contrato c
where
c.QtdParcelasFalta > 0
and (case
when c.DiaEspecificoMarcar = 1
then c.DiaEspecifico
when c.DiaEspecificoMarcar = 0
then (select convert(int, substring(DataCobranca, 2, 2))
from Contrato
where Contrato.Id = c.Id) -
(select e.DataProcessamentoNota
from Contrato t
inner join PedidoVenda p on p.id = t.PedidoVendaId
inner join Empresas e on p.EmpresaID = e.Id
where p.id = t.PedidoVendaId
and t.id = c.Id and p.EmpresaID = 1)
end) = (SELECT DAY(GETDATE()))
I tried it like this, but it didn't work out, did not pass the correct values, because I'm not aware of pass to Entity Framework:
var contrato = db.Contrato
.Include(a => a.PedidoVenda)
.Include(a => a.Cliente)
.Where(a => a.PedidoVenda.EmpresaID == model.EmpresaID
&& a.Cancelado == false
&& a.DiaEspecificoMarcar == true
&& a.DiaEspecifico == int.Parse(DateTime.Now.ToString("dd")) ||
(int.Parse(a.DataCobranca.Substring(1, 2)) - a.PedidoVenda.Empresa.DataProcessamentoNota)
== int.Parse(DateTime.Now.ToString("dd"))
).ToList();
You are actually on the right track. You just need to add when conditions to your lef and right conditions like this:
var contrato = db.Contrato.Include(a => a.PedidoVenda).Include(a => a.Cliente).Where
(a => a.PedidoVenda.EmpresaID == model.EmpresaID && a.Cancelado == false &&
a.DiaEspecificoMarcar == false && a.DiaEspecifico == int.Parse(DateTime.Now.ToString("dd")) ||
( a.DiaEspecificoMarcar == true && int.Parse(a.DataCobranca.Substring(1, 2)) - a.PedidoVenda.Empresa.DataProcessamentoNota)
== int.Parse(DateTime.Now.ToString("dd"))
).ToList();
I also suggest you use DateTime.Now from a variable to be sure both int.Parse gets the same input

LINQ to Entities: Convert SQL Sub Select

I got this figured out.
No need to answer.
The system says I have to wait 8 hours before answering my own questions. But for now the answer is below:
Here is the answer:
var startDate = DateTime.Today.AddDays(-30);
var results = (from h in Histories
join q in Quotes
on h.QuoteID equals q.QuoteID
join a in Agencies
on q.AgencyID equals a.AgencyID
where q.Status == "Inforce" &&
q.LOB == "Vacant" &&
q.EffectiveDate > startDate &&
h.Deleted == null &&
h.DeprecatedBy == null &&
h.TransactionStatus == "Committed" &&
a.DC_PLT_Roles.Any(r => r.Name == "Wholesaler")
group new {h} by new {h.PolicyNumber} into g
select new {
MaxHistoryID = g.Max (x => x.h.HistoryID),
comment = (from h2 in Histories
where h2.HistoryID == g.Max (x => x.h.HistoryID)
select h2.Comment).FirstOrDefault()
}).ToList();
The key code was:
comment = (from h2 in Histories
where h2.HistoryID == g.Max (x => x.h.HistoryID)
select h2.Comment).FirstOrDefault()
We are in the process of converting SQL / Stored Procedures to LINQ to Entities statements. And I can’t figure out the proper syntax for a sub select.
Currently I am converting this SQL:
declare #startDate DateTime
set #startDate = DATEADD(DD, -30, GETDATE())
select * from history where historyid in(
select MAX(h.historyid) as HistoryId
from History h (nolock)
inner join Quote q (nolock) on h.QuoteID = q.QuoteID
inner join Agency (nolock) a on q.AgencyID = a.AgencyID
inner join DC_PLT_EntityRoles er (nolock) on a.AgencyID = er.EntityID
inner join DC_PLT_Roles (nolock) r on er.RoleID = r.RoleID
where
q.Status = 'Inforce'
and q.LOB = 'Vacant'
and q.EffectiveDate > #startDate
and h.Deleted is null --
and h.DeprecatedBy is null --
and h.TransactionStatus = 'Committed'
and r.Name = 'Wholesaler'
group by h.PolicyNumber)
As you can see the code above is made up of two select statements. The main select (select * from history).. And a filter select (select MAX(h.historyid)…)
I got the filter select working (See below):
var startDate = DateTime.Today.AddDays(-30);
var results = (from h in Histories
join q in Quotes
on h.QuoteID equals q.QuoteID
join a in Agencies
on q.AgencyID equals a.AgencyID
where q.Status == "Inforce" &&
q.LOB == "Vacant" &&
q.EffectiveDate > startDate &&
h.Deleted == null &&
h.DeprecatedBy == null &&
h.TransactionStatus == "Committed" &&
a.DC_PLT_Roles.Any(r => r.Name == "Wholesaler")
group new {h} by new {h.PolicyNumber} into g
select new {
MaxHistoryID = g.Max (x => x.h.HistoryID)
}).ToList();
However I can’t figure out the proper syntax to set up the main select. (Basically getting the records from the History table using the HistoryID from the filter select.)
Any help would be appreciated.
Thanks for your help.
I figured it out, here is the code:
var startDate = DateTime.Today.AddDays(-30);
var results = (from h in Histories
.Include("Quote")
.Include("Quote.Agency")
where h.Quote.Status == "Inforce" &&
h.Quote.LOB == "Vacant" &&
h.Quote.EffectiveDate > startDate &&
h.Deleted == null &&
h.DeprecatedBy == null &&
h.TransactionStatus == "Committed" &&
h.Quote.Agency.DC_PLT_Roles.Any(r => r.Name == "Wholesaler")
group new {h} by new {h.PolicyNumber} into g
select new {
XMLData = (from h2 in Histories
where h2.HistoryID == g.Max (x => x.h.HistoryID)
select h2.XMLData).FirstOrDefault()
}).ToList();
The key logic is:
select new {
XMLData = (from h2 in Histories
where h2.HistoryID == g.Max (x => x.h.HistoryID)
select h2.XMLData).FirstOrDefault()
}).ToList();
Gotta love the Nested Query

set value from select for few select

I have select, iside select have 2 column. This column must be filled from same select, but I don't want use select twice for it. Is it possoble use select 1 time and after that set second column value from first?
Example:
insert into #temptable from
select
a = (select aa from table1 where quantity > 5)
b = (select aa from table1 where quantity > 5)
I need:
insert into #temptable from
select
a = (select aa from table1 where quantity > 5)
b = {value from a}
Update. I wrote bad example, I need set to BalancePrediction1 and BalancePrediction2 value from Balance
INSERT #tmpBalances
SELECT PA.ContractId AS 'ContractId',
Con.Name AS 'ContractName',
Bal.PortfolioAccountId AS 'PortfolioAccountId',
PA.Name AS 'PortfolioAccountName',
RA.GeneralId AS 'RegisterAccountGeneralId',
Bal.BalanceTypeId AS 'BalanceTypeId',
Bt.Name AS 'BalanceTypeName',
Bt.Type AS 'BalanceTypeType',
Bal.BalanceTimeType AS 'BalanceTimeType',
Bal.InstrumentId AS 'InstrumentId',
Ins.Name AS 'InstrumentName',
Ins.GeneralId AS 'InstrumentGeneralId',
(Bal.Balance -
(
SELECT COALESCE(SUM(Mov.Amount), 0)
FROM trd.Movements AS Mov
WHERE
Bal.InstrumentId = Mov.InstrumentId AND
Bal.PortfolioAccountId = Mov.PortfolioAccountId AND
Bal.BalanceTypeId = Mov.BalanceTypeId AND
Bal.BalanceTimeType = Mov.BalanceTimeType AND
DateDiff(DAY, #Date, Mov.Date) > 0 AND
-- Currency může být null a NULL = NULL nejde
COALESCE(Bal.CurrencyId, -1) = COALESCE(Mov.CurrencyId, -1)
)
) as Balance,
Balance AS 'BalancePrediction1',
Balance AS 'BalancePrediction2',
Bal.CurrencyId AS 'CurrencyId',
Ccy.Code AS 'CurrencyCode',
PA.PositionServiceType 'PositionServiceType',
Ccy.Name 'CurrencyName',
S.Nominal AS 'Nominal',
S.NominalCurrencyId AS 'NominalCurrencyId',
trd.GetCurrencyCode(S.NominalCurrencyId) AS 'NominalCurrencyCode'
FROM trd.Balances AS Bal
JOIN trd.PortfolioAccounts AS PA ON PA.Id = Bal.PortfolioAccountId
JOIN trd.Contracts AS Con ON Con.Id = PA.ContractId
JOIN trd.RegisterAccounts AS RA ON RA.Id = PA.RegisterAccountId
JOIN trd.BalanceTypes AS Bt ON Bt.Id = Bal.BalanceTypeId
JOIN trd.Instruments AS Ins ON Ins.Id = Bal.InstrumentId
LEFT OUTER JOIN trd.Currencies AS Ccy ON Ccy.Id = Bal.CurrencyId
LEFT JOIN trd.SecuritiesView S ON s.Id = Ins.Id AND DateDiff(d, S.ValidFrom, #Date) >= 0 AND (S.ValidTo IS NULL OR DateDiff(d, S.ValidTo, #Date) < 0)
AND S.InstrumentInstrumentTypePriceUnit = 1
You could do an update to the table variable after the insert.
update #tmpBalances
set BalancePrediction1 = Balance,
BalancePrediction2 = Balance
Or you can use cross apply to calculate the sum.
INSERT #tmpBalances
SELECT PA.ContractId AS 'ContractId',
Con.Name AS 'ContractName',
Bal.PortfolioAccountId AS 'PortfolioAccountId',
PA.Name AS 'PortfolioAccountName',
RA.GeneralId AS 'RegisterAccountGeneralId',
Bal.BalanceTypeId AS 'BalanceTypeId',
Bt.Name AS 'BalanceTypeName',
Bt.Type AS 'BalanceTypeType',
Bal.BalanceTimeType AS 'BalanceTimeType',
Bal.InstrumentId AS 'InstrumentId',
Ins.Name AS 'InstrumentName',
Ins.GeneralId AS 'InstrumentGeneralId',
(Bal.Balance - Mov.SumAmount) AS Balance,
(Bal.Balance - Mov.SumAmount) AS 'BalancePrediction1',
(Bal.Balance - Mov.SumAmount) AS 'BalancePrediction2',
Bal.CurrencyId AS 'CurrencyId',
Ccy.Code AS 'CurrencyCode',
PA.PositionServiceType 'PositionServiceType',
Ccy.Name 'CurrencyName',
S.Nominal AS 'Nominal',
S.NominalCurrencyId AS 'NominalCurrencyId',
trd.GetCurrencyCode(S.NominalCurrencyId) AS 'NominalCurrencyCode'
FROM trd.Balances AS Bal
JOIN trd.PortfolioAccounts AS PA ON PA.Id = Bal.PortfolioAccountId
JOIN trd.Contracts AS Con ON Con.Id = PA.ContractId
JOIN trd.RegisterAccounts AS RA ON RA.Id = PA.RegisterAccountId
JOIN trd.BalanceTypes AS Bt ON Bt.Id = Bal.BalanceTypeId
JOIN trd.Instruments AS Ins ON Ins.Id = Bal.InstrumentId
LEFT OUTER JOIN trd.Currencies AS Ccy ON Ccy.Id = Bal.CurrencyId
LEFT JOIN trd.SecuritiesView S ON s.Id = Ins.Id AND DateDiff(d, S.ValidFrom, #Date) >= 0 AND (S.ValidTo IS NULL OR DateDiff(d, S.ValidTo, #Date) < 0)
AND S.InstrumentInstrumentTypePriceUnit = 1
CROSS APPLY (SELECT COALESCE(SUM(Mov.Amount), 0)
FROM trd.Movements AS Mov
WHERE
Bal.InstrumentId = Mov.InstrumentId AND
Bal.PortfolioAccountId = Mov.PortfolioAccountId AND
Bal.BalanceTypeId = Mov.BalanceTypeId AND
Bal.BalanceTimeType = Mov.BalanceTimeType AND
DateDiff(DAY, #Date, Mov.Date) > 0 AND
-- Currency může být null a NULL = NULL nejde
COALESCE(Bal.CurrencyId, -1) = COALESCE(Mov.CurrencyId, -1)
) Mov(SumAmount)
SELECT aa AS a, aa AS b
FROM table1
WHERE quantity > 5
One way;
;with T (value) as (
select aa from table1 where quantity > 5
)
insert into #temptable
select value, value from T