How to do this SQL in LINQ - sql-server

Morning i would like to know how to do this bit of (MS) SQL in LINQ...
SELECT CONVERT(CHAR(10),orderDate,110) AS OrderDate,
SUM(1) AS TotalOrders
FROM Orders
WHERE OrderDate>getdate()-30
GROUP BY CONVERT(CHAR(10),orderDate,110)
ORDER BY OrderDate DESC
Many thanks in advance.
UPDATE
I ended using and edited version of the solutions provided below, thought i would share it...
using (DataDataContext dc = new DataDataContext())
{
var query = from o in dc.Orders
where o.orderDate > DateTime.Now.AddDays(-30)
let dt = o.orderDate
group o by new DateTime(dt.Year, dt.Month, dt.Day) into g
select new OrderCounts
{
OrderDate = String.Format("{0:d}", g.Key.Date),
TotalOrders = g.Count()
};
query.GroupBy(o => o.OrderDate);
query.OrderBy(o => o.OrderDate);
return query.ToList();
}

var result =(from s in Orders
where s.OrderDate > DateTime.Now.AddDays(-30)
group s by new { date = s.OrderDate.ToString() } into g
// or use ((DateTime)s.OrderDate).ToShortDateString() instead of s.OrderDate.ToString()
select new
{
OrderDate = g.Key.date,
TotalOrders = g.Count()
}).OrderByDescending(x=>x.OrderDate);;

The query will be
var query = from o in res
where o.OrderDate > DateTime.Now.AddDays(-30)
orderby o.OrderDate descending
group o by o.OrderDate into g
select new
{
OrderDate = g.Key.Date.ToString("MM/dd/yyyy")
,
TotalOrders = g.Sum(i=> 1)
};
OR by Lambda expression
var query= res
.Where(i => i.OrderDate > DateTime.Now.AddDays(-30))
.OrderByDescending(o => o.OrderDate)
.GroupBy(g => g.OrderDate)
.Select(s => new { OrderDate = s.Key.Date.ToString("MM/dd/yyyy"), TotalOrders = s.Sum(i => 1) });

Related

Convert SQL query to Linq2db

Some one help me to convert SQL query to linq2db join query.
Below is my query.
var query = from a in _accountRepository.Table
join b in _documentRepository.Table on a.ID equals b.AccountID
join c in _documentTypeRepository.Table on b.DocumentTypeID equals c.ID
where a.CompanyID == companyID && b.CompanyID == companyID
&& c.CompanyID == companyID
&& a.IsActive && !a.IsDeleted && c.IsInvoice
&& b.IsActive && !b.IsDeleted
&& b.Date.Date >= fromDate.Date && b.Date.Date <=
toDate.Date
&& (b.AccountID == accountID || accountID == null)
&& (costcenterID.Contains(b.CostCenterID) || costcenterID == null)
&& a.AccountTypeID == (int)DefaultAccountTypes.Customer
group b by new { a.DisplayName, a.ID } into g
select new SalesByCustomerModel
{
AccountID = g.Key.ID,
DisplayName = g.Key.DisplayName,
InvoiceCount = g.Count(),
Sales = g.Sum(x => (x.SubTotal - x.Discount)),
SalesWithTax = g.Sum(x => x.Total),
Tax = g.Sum(x => x.Tax)
};
I have to add this. How can I achive with linq2db.
INNER JOIN ( SELECT ROW_NUMBER() OVER(PARTITION by DocumentID ORDER BY DocumentID) AS SrNo,
DocumentID
FROM DocumentDetail
WHERE (DocumentItemID = #itemID OR #itemID IS NULL)
AND CompanyID = #companyID ) D ON D.DocumentID = B.ID AND SrNo = 1
Linq2db supports window functions, and we can write details subquery and add join:
var details =
from d in _documentDetailRepository.Table
where (d.DocumentItemID == itemID || itemID == null)
&& d.CompanyID == companyID
select new
{
d.DocumentID,
SrNo = Sql.Ext.RowNumber().Over()
.PartitionBy(d.DocumentID)
.OrderBy(d.DocumentID)
.ToValue()
};
// Then your query can be extended
var query =
from a in _accountRepository.Table
join b in _documentRepository.Table on a.ID equals b.AccountID
join d in details on new { DocumentID = b.Id, SrNo = 1 } equals new { d.DocumentID, d.SrNo }
...

Do I have to loop through an IEnumerable return from Dapper even though I only return a single object?

I'm using Dapper to retrieve employee information when I select that employee from a list. Everything maps correctly, and then the rows are grouped according to employee.id. Just what I want. But Dapper returns an IEnumerable, which makes sense when I query for multiple employees and have to make multiple objects; but it makes less sense when I'm only returning the one. Is there a solution to this, or do I just need to loop through the single item? Here's my code:
public async Task<List<EmployeeModel>> GetSelectedEmployee(int selectedEmployeeID)
{
using (IDbConnection connection = new System.Data.SqlClient.SqlConnection(GlobalConfig.CnnString("WorkDeskDB")))
{
var par = new
{
SelectedEmployeeID = selectedEmployeeID
};
var sql = #"SELECT e.id, e.FirstName, e.LastName, e.Nickname,
em.EmployeeID, em.Address, em.Type,
e.JobTitleID, jt.id, jt.Name,
p.EmployeeID, p.Number, p.Type,
ect.EmployeeID, ect.NameID, ect.InitialDate, ect.ExpirationDate,
ct.id, ct.Name
FROM dbo.Employees e
LEFT JOIN dbo.Emails em ON em.EmployeeID = e.id
LEFT JOIN dbo.JobTitles jt ON e.JobTitleID = jt.id
LEFT JOIN Phones p ON p.EmployeeID = e.id
LEFT JOIN dbo.EmployeeCertificationType ect ON ect.EmployeeID = e.id
LEFT JOIN dbo.CertificationType ct ON ect.NameID = ct.id
WHERE e.id = #SelectedEmployeeID";
var employees = await connection.QueryAsync<EmployeeModel, EmailModel, TitleModel, PhoneModel, CertificationModel, EmployeeModel>(sql, (e, em, t, p, c) =>
{
e.EmailList.Add(em);
e.JobTitle = t;
e.PhoneList.Add(p);
e.CertificationList.Add(c);
return e;
},
par, splitOn: "EmployeeID, JobTitleID, EmployeeID, EmployeeID");
var result = employees.GroupBy(e => e.ID).Select(g =>
{
var groupedEmployee = g.First();
groupedEmployee.EmailList = g.Select(e => e.EmailList.Single()).ToList();
return groupedEmployee;
});
return result.ToList();
}
}
You only have one Employee. The other rows are because an Employee can have multiple Phones, Emails and Certifications.
I suggest you do something like this:
EmployeeModel employee = null;
await connection.QueryAsync<EmployeeModel, EmailModel, TitleModel, PhoneModel, CertificationModel, EmployeeModel>(sql, (e, em, t, p, c) =>
{
if (employee is null)
{
employee = e;
employee.JobTitle = t;
}
employee.EmailList.Add(em);
employee.PhoneList.Add(p);
employee.CertificationList.Add(c);
return employee;
},
par, splitOn: "EmployeeID, JobTitleID, EmployeeID, EmployeeID");
// go on using employee, no need for the employees list ...
Then you skip the afterburning of the list.
My suggestion is that you replace the call connection.QueryAsync<EmployeeModel> by other that returns only one element, as stated here

Does the left join order matter in linq query (EF Core 2)?

I have book table which has a relationship with three tables UserFavorites, UserRates, DiscountItems and last one (DiscountItems) has a relationship with Discounts table so I want to load discount with book if it exist
When create linq left join query with this order (join userfavoirtes then discountitems then discount then userate) generated SQL code is fine as expected
But when change order like below (join userfavoirtes then userate then discountitems then discount) generated query only contain first two join only
var books = (from b in result
join uf in UnitOfWork.Context.UserFavorites
on new { b.Id, RelatedType = RelatedTypeEnum.Book, UserId = userId }
equals new { Id = uf.RelatedId, uf.RelatedType, uf.UserId } into buf
from f in buf.DefaultIfEmpty()
join di in UnitOfWork.Context.DiscountItems
on b.Id equals di.BookId into bdi
from di in bdi.DefaultIfEmpty()
join d in UnitOfWork.Context.Discounts
on (di != null ? di.DiscountId : 0) equals d.Id into bd
from d in bd.DefaultIfEmpty()
join ur in UnitOfWork.Context.UserRates
on new { b.Id, UserId = userId }
equals new { Id = ur.BookId, UserId = ur.CreatedBy } into bur
from r in bur.DefaultIfEmpty()
select new BookViewModel
{
Id = b.Id,
Title = b.Title,
Price = b.Price,
BookImage = SetDefaultImageIfNoImage(b.BookImage),
IsFavorite = f != null ? f.IsFavorite : false,
Rate = bur.Any() ? Math.Round(bur.Average(a => a.Value), 1) : 0,
Discount = d
})
.OrderBy(a => a.CategoryId)
.ThenBy(a => a.Authors)
.Take(10).ToList();
this is generated sql query
SELECT *FROM [Book] AS [a]
LEFT JOIN [UserFavorites] AS [uf] ON (([a].[Id] = [uf].[RelatedId]) AND (3 = [uf].[RelatedType])) AND [uf].[UserId] IS NULL
LEFT JOIN [DiscountItems] AS [di] ON [a].[Id] = [di].[BookId]
LEFT JOIN [Discounts] AS [d] ON CASE
WHEN [di].[Id] IS NOT NULL
THEN [di].[DiscountId] ELSE 0
END = [d].[Id]
LEFT JOIN [UserRates] AS [ur] ON ([a].[Id] = [ur].[BookId]) AND [ur].[CreatedBy] IS NULL
WHERE ((([a].[Active] = 1) AND ([a].[Id] <> 62)) AND ([a].[Status] = 1))
but when write join with this order
var books = (from b in result
join uf in UnitOfWork.Context.UserFavorites
on new { b.Id, RelatedType = RelatedTypeEnum.Book, UserId = userId }
equals new { Id = uf.RelatedId, uf.RelatedType, uf.UserId } into buf
from f in buf.DefaultIfEmpty()
join ur in UnitOfWork.Context.UserRates
on new { b.Id, UserId = userId }
equals new { Id = ur.BookId, UserId = ur.CreatedBy } into bur
from r in bur.DefaultIfEmpty()
join di in UnitOfWork.Context.DiscountItems
on b.Id equals di.BookId into bdi
from di in bdi.DefaultIfEmpty()
join d in UnitOfWork.Context.Discounts
on (di != null ? di.DiscountId : 0) equals d.Id into bd
from d in bd.DefaultIfEmpty()
select new BookViewModel
{
Id = b.Id,
Title = b.Title,
Price = b.Price,
BookImage = SetDefaultImageIfNoImage(b.BookImage),
IsFavorite = f != null ? f.IsFavorite : false,
Rate = bur.Any() ? Math.Round(bur.Average(a => a.Value), 1) : 0,
Discount = d
})
.OrderBy(a => a.CategoryId)
.ThenBy(a => a.Authors)
.Take(10).ToList();
generated SQL query contains only the first two joins
SELECT *
FROM [Book] AS [a]
LEFT JOIN [UserFavorites] AS [uf] ON (([a].[Id] = [uf].[RelatedId]) AND (3 = [uf].[RelatedType])) AND [uf].[UserId] IS NULL
LEFT JOIN [UserRates] AS [ur] ON ([a].[Id] = [ur].[BookId]) AND [ur].[CreatedBy] IS NULL
WHERE ((([a].[Active] = 1) AND ([a].[Id] <> 62)))

SQL query select

I am using MSSQL Server and Nodejs with npm mssql. I need to build a query.
Explanation:
Need to select Users from table that did not receive emails today or never receive.
Query example:
SELECT * FROM dbo.Users u
LEFT JOIN dbo.userEmailHistory ueh
ON u.id = ueh.userId
WHERE IsNull(sDate, '') = ''
OR CONVERT(date,sDate)>=CONVERT(date,DATEADD(day,1,getdate()))
Then:
Need to select the user favorite brand. I am doing async. So the code is looking like this:
function getUserSalesByMalls(params, callback) {
var usersArray = [];
var targetID = params.type;
async.eachLimit(params, 1, function (user, cb) {
sqlRequest("
SELECT TOP 1 bts.BrandCategoryID as title, b.title as brand, b.id
FROM dbo.Users st JOIN SaleView ss ON (st.ID=ss.userID)
JOIN Sales sa ON (sa.ID=ss.SaleID)
JOIN Brands b ON (b.ID=sa.BrandID)
JOIN KEY_BrandcategoryToSale bts ON (bts.SaleID=sa.ID)
WHERE st.ID="+**user.id**+"
GROUP BY bts.BrandCategoryID, b.title, b.id
ORDER BY COUNT(bts.BrandCategoryID) desc",
function (err, result) {
user.favBrand = result;
console.log(user);
usersArray.push(user);
cb();
})
}, function () {
callback(null, usersArray)
})
}
Then:
I need to select top 2 sales by user favorite brand that were most viewed in period 14 days and user never seen it:
function getUserSalesByMalls(params, callback) {
var usersArray = [];
var targetID = params.type;
async.eachLimit(params, 1, function (user, cb) {
sqlRequest("
`SELECT DISTINCT TOP 2 s.id as saleId, s.title, s.description, s.imageUrl, count(sv.saleId) as mostViewsPeriod14Days, s.guid, stm.mallId as mallId, brand.title as brandTitle FROM dbo.Sales s
INNER JOIN dbo.SalesToMall stm ON s.id = stm.saleId
INNER JOIN dbo.SaleView sv ON s.id = sv.saleId
INNER JOIN dbo.Brands brand ON s.brandID = brand.id
WHERE (sv.date <= GETDATE())
AND (sv.date >= GETDATE() - 14) AND s.isActive = 1 AND s.isHotSale = 1 AND b.id = "+user.favBrandId+"
AND s.id NOT IN (SELECT DISTINCT sv2.saleId FROM dbo.SaleView sv2
WHERE sv2.userId = "+user.id+")
GROUP BY s.id, s.title, s.description, s.imageUrl, s.guid, stm.mallId, brand.title
ORDER BY COUNT(sv.saleId) DESC`",
function (err, result) {
user.salesByBrand = result;
console.log(user);
usersArray.push(user);
cb();
})
}, function () {
callback(null, usersArray)
})
}
And then last one: i need to select 3 suggestions for the user by mall id that were most viewed in period 14 days and user never seen it:
function getUserSalesByMalls(params, callback) {
var usersArray = [];
var targetID = params.type;
async.eachLimit(params, requestPerLimit, function (user, cb) {
setTimeout(function () {
sqlRequest("SELECT DISTINCT TOP 3 s.id as saleId, s.title, s.description, s.imageUrl, count(sv.saleId) as mostViewsPeriod14Days, s.guid, stm.mallId as mallId, brand.title as brandTitle
FROM dbo.Sales s
INNER JOIN dbo.SalesToMall stm ON s.id = stm.saleId
INNER JOIN dbo.SaleView sv ON s.id = sv.saleId
INNER JOIN dbo.Brands brand ON s.brandID = brand.id
WHERE (sv.date <= GETDATE())
AND (sv.date >= GETDATE() - 14)
AND s.isActive = 1 AND s.isHotSale = 1
AND stm.mallId = "+user.mallId+"
AND s.id NOT IN (SELECT DISTINCT sv2.saleId
FROM dbo.SaleView sv2
WHERE sv2.userId = "+user.id+")
GROUP BY s.id, s.title, s.description, s.imageUrl, s.guid, stm.mallId, brand.title
ORDER BY COUNT(sv.saleId) DESC", function (err, result) {
if (!result) {
cb();
} else if (result.length == 3) {
sqlInsert("INSERT INTO UserEmailHistory (userID,sDate,targetID) VALUES (" + user.id + ",CONVERT(datetime,DATEADD(hour," + utc_diff + ",getdate()))," + targetID + ")");
console.log("USER WITH 3 SALES BY MALL");
user.sales = result;
console.log(user);
usersArray.push(user);
cb();
}
})
}, requestPerMillisecond)
}, function () {
callback(null, usersArray)
})
}
My question is:
Is there any way to combine and build only one query and get all necessary data regarding my explanation?

Query Slow in Linq, Fast in LinqPad, SQL Management Studio and SQL Profiler

I have this linq query i'm using and it's taking 50 seconds to run when i am running it my asp.net application, however the same query executes in 500ms in LinqPad and Sql Management Studio.
I even took the query from the SQL Profiler and ran it again in SQL Management Studio and it takes around 500ms. What overhead Linq could be doing, that an extra 49s??
Below is the code for reference, thanks for your help.
var rCampaign =
(from a in db.AdCreative
join h in db.AdHit on a.ID equals h.AdID into gh
join l in db.AdGroup_Location on a.AdGroupID equals l.AdGroupID into gj
from subloc in gj.DefaultIfEmpty()
from subhits in gh.DefaultIfEmpty()
where a.AdGroup.AdHost.Select(q => q.ID).Contains(rPlatform.ID) &&
a.AdGroup.AdPublisher.Select(q => q.ID).Contains(rPublisher.ID) &&
a.AdDimensionID == AdSize &&
a.AdGroup.Campaign.Starts <= rNow &&
a.AdGroup.Campaign.Ends >= rNow &&
subhits.HitType == 1 &&
(subloc == null || subloc.LocationID == rLocationID)
select new {
ID = a.ID,
Name = a.Name,
Spent = (subhits.AdDimension != null) ? ((double)subhits.AdDimension.Credit / 1000) : 0,
CampaignID = a.AdGroup.Campaign.ID,
CampaignName = a.AdGroup.Campaign.Name,
CampaignBudget = a.AdGroup.Campaign.DailyBudget
}).GroupBy(adgroup => adgroup.ID)
.Select(adgroup => new {
ID = adgroup.Key,
Name = adgroup.FirstOrDefault().Name,
Spent = adgroup.Sum(q => q.Spent),
CampaignID = adgroup.FirstOrDefault().CampaignID,
CampaignName = adgroup.FirstOrDefault().CampaignName,
CampaignBudget = adgroup.FirstOrDefault().CampaignBudget,
})
.GroupBy(q => q.CampaignID)
.Select(campaigngroup => new {
CampaignID = campaigngroup.Key,
DailyBudget = campaigngroup.FirstOrDefault().CampaignBudget,
Consumed = campaigngroup.Sum(q => q.Spent),
RemainningCredit = campaigngroup.FirstOrDefault().CampaignBudget - campaigngroup.Sum(q => q.Spent),
Ads = campaigngroup.Select(ag => new {
ID = ag.ID,
Name = ag.Name,
Spent = ag.Spent
}).OrderBy(q => q.Spent)
})
.Where(q => q.Consumed <= q.DailyBudget).OrderByDescending(q => q.RemainningCredit).First();
There are a few ways you can simplify that query:
select into lets you keep it all in query syntax.
The join ... into/from/DefaultIfMany constructs implementing left joins can be replaced with join ... into construcs representing group joins.
Some of the groups near the end cannot be empty, so FirstOrDefault is unnecessary.
Some of the where conditions can be moved up to the top before the query gets complicated.
Here's the stab I took at it. The revisions were significant, so it might need a little debugging:
var rCampaign = (
from a in db.AdCreative
where a.AdDimensionID == AdSize &&
a.AdGroup.Campaign.Starts <= rNow &&
a.AdGroup.Campaign.Ends >= rNow &&
a.AdGroup.AdHost.Select(q => q.ID).Contains(rPlatform.ID) &&
a.AdGroup.AdPublisher.Select(q => q.ID).Contains(rPublisher.ID)
join hit in db.AdHit.Where(h => h.HitType == 1 && h.LocationID == rLocationID)
on a.ID equals hit.AdID
into hits
join loc in db.AdGroup_Location
on a.AdGroupID equals loc.AdGroupID
into locs
where !locs.Any() || locs.Any(l => l.LocationID == rLocationID)
select new {
a.ID,
a.Name,
Spent = hits.Sum(h => h.AdDimension.Credit / 1000) ?? 0,
CampaignID = a.AdGroup.Campaign.ID,
CampaignName = a.AdGroup.Campaign.Name,
CampaignBudget = a.AdGroup.Campaign.DailyBudget,
} into adgroup
group adgroup by adgroup.CampaignID into campaigngroup
select new
{
CampaignID = campaigngroup.Key,
DailyBudget = campaigngroup.First().CampaignBudget,
Consumed = campaigngroup.Sum(q => q.Spent),
RemainingCredit = campaigngroup.First().CampaignBudget - campaigngroup.Sum(q => q.Spent),
Ads = campaigngroup.Select(ag => new {
ag.ID,
ag.Name,
ag.Spent,
}).OrderBy(q => q.Spent)
} into q
where q.Consumed <= q.DailyBudget
orderby q.RemainingCredit desc)
.First()
I refactored using Query syntax (Not sure if it improved readability). Removed one group by. Made some minor adjustments (replaced FirstOrDefault with Key property, changed Contains to Any). Hopefully it has some effect of speed.
var rCampaign = (from cg in
(from a in db.AdCreative
from subhits in db.AdHit.Where(h => a.ID == h.AdID)
.DefaultIfEmpty()
from subloc in db.AdGroup_Location.Where(l => a.AdGroupID == l.AdGroupID)
.DefaultIfEmpty()
where a.AdGroup.AdHost.Any(q => q.ID == rPlatform.ID) &&
a.AdGroup.AdPublisher.Any(q => q.ID == rPublisher.ID) &&
a.AdDimensionID == AdSize &&
a.AdGroup.Campaign.Starts <= rNow &&
a.AdGroup.Campaign.Ends >= rNow &&
subhits.HitType == 1 &&
(subloc == null || subloc.LocationID == rLocationID)
group new { a, subhits } by new { ID = a.ID, a.Name, CampaignID = a.AdGroup.Campaign.ID, CampaignName = a.AdGroup.Campaign.Name, CampaignBudget = a.AdGroup.Campaign.DailyBudget } into g
select new
{
ID = g.Key.ID,
Name = g.Key.Name,
Spent = g.Sum(x => (x.subhits.AdDimension != null) ? ((double)subhits.AdDimension.Credit / 1000) : 0),
CampaignID = g.Key.CampaignID,
CampaignName = g.Key.CampaignName,
CampaignBudget = g.Key.CampaignBudget
})
group cg by new { cg.CampaignID, cg.CampaignBudget } into cg
let tempConsumed = cg.Sum(q => q.Spent)
let tempRemainningCredit = cg.Key.CampaignBudget - tempConsumed
where tempConsumed <= cg.Key.CampaignBudget
orderby tempRemainningCredit desc
select new
{
CampaignID = cg.Key.CampaignID,
DailyBudget = cg.Key.CampaignBudget,
Consumed = tempConsumed,
RemainningCredit = tempRemainningCredit,
Ads = from ag in cg
orderby ag.Spent
select new
{
ID = ag.ID,
Name = ag.Name,
Spent = ag.Spent
}
}).First();

Resources