Linq query efficiency using Entity Framework - asp.net
I have to rewrite a huge SQL query that gets data from around 10 tables using Entity Framework and Linq. In short, the query gets a list of products from the main table, then fetches other information like download count, sales count, author, etc. from other tables for those products.
What I decided to do was break it down into parts so that its easy for others to understand and edit.
First, I get the list of products. Then, I get a list data for the other columns and I merge everything together in the last step.
var mainTableQuery = from p in context.mains
select new
{
p.ProductID,
p.title,
p.department_id,
p.TotalInStock
};
//Getting the top author by priority for every product ID
var authorLinkQuery= from authorLink in context.AuthorLinks
group authorLink by authorLink.ProductID
into groups
select groups.OrderBy(p=>p.Priority).FirstOrDefault();
// Link productIDs with primary author names
var authorsFinalQuery = from author in context.Authors
join authorLink in authorLinkQuery
on author.AuthorID equals authorLink.AuthorID
select new
{
authorLink.ProductID,
Name = (String.IsNullOrEmpty(author.Company) ? author.FirstName + " " + author.LastName : author.Company)
};
var finalQuery = from main in mainTableQuery
join author in authorsFinalQuery
on main.ProductID equals author.ProductID
select new
{
main,
author.Name
};
This final query gets the correct data but it takes around 30s. The original SQL server query took only 6s. The problem is that the SQL server query that is generated by entity framework is very inefficient. Is there a way to optimize this?
EDIT: The complete stored procedure that I'm trying to replace is:
CREATE PROCEDURE [dbo].[usp_AllProducts] (#ProgramAreaID int,
#CustomDateStart datetime,
#CustomDateEnd datetime,
#ShowNLA nvarchar(50))
AS
BEGIN
SET NOCOUNT ON;
IF #ProgramAreaID = 1000
BEGIN
SELECT TOP (100) PERCENT
BaseInventory.ProductID,
BaseInventory.ReferenceNumber,
BaseInventory.Title,
BaseInventory.StoredBy,
BaseInventory.TotalInStock,
BaseInventory.StockAtEDC,
BaseInventory.Cost,
BaseInventory.RetailPrice,
BaseInventory.PubDate,
BaseInventory.DepartmentCode,
vwAuthor.PrimaryAuthor,
ISNULL(Sales30Days.QuantitySold, 0) AS Last30Days,
ISNULL(SalesPastYear.QuantitySold, 0) AS Last365Days,
ISNULL(CustomRangeSales.QuantitySold, 0) AS CustomRange,
ISNULL(SalesPastYear.ZeroStock, '12/31/9999') AS ZeroStock,
ISNULL(SalesPastYear.ZeroStockFullDate, CONVERT(datetime, '12/31/9999', 102)) AS ZeroStockFullDate,
BaseInventory.FullPubDate,
BaseInventory.ProgramArea,
BaseInventory.Spaces,
BaseInventory.DigitalFileExists,
BaseInventory.DownloadCount,
BaseInventory.DownloadCountCustom,
ISNULL(SalesPastYear.SpacesSold, 0.000) AS SpacesSold,
BaseInventory.DateReceived,
BaseInventory.ProductWeight,
BaseInventory.NumberOfPages,
BaseInventory.DigitalFileCount,
BaseInventory.ActiveDigitalFileCount
FROM (SELECT TOP (100) PERCENT
m.ProductWeight,
m.ProductID,
m.reference_number AS ReferenceNumber,
m.title AS Title,
MAX(sb.StoredBy) AS StoredBy,
m.TotalInStock,
m.edc_copies AS StockAtEDC,
m.pub_cost AS Cost,
m.RetailPrice,
m.pub_date AS PubDate,
d.department_code AS DepartmentCode,
m.department_id AS DepartmentId,
dg.department_group AS ProgramArea,
m.FullPubDate,
ISNULL(Boxes.Spaces, CASE
WHEN sb.StoredBy = 'WWW' THEN 0
ELSE 1
END) AS Spaces,
CASE
WHEN ISNULL(dm.FileID, 0) = 0 THEN 'N/A'
ELSE 'Active'
END AS DigitalFileExists,
ISNULL(DLs.DownloadCount, 0) AS DownloadCount,
ISNULL(DLsCustom.DownloadCountCustom, 0) AS DownloadCountCustom,
MAX(history.DateReceived) AS DateReceived,
ISNULL(m.number_of_pages, 'N/A') AS NumberOfPages,
(SELECT
COUNT(*)
FROM tblDigitalMedia tD
WHERE tD.ProductID = m.ProductID)
AS DigitalFileCount,
(SELECT
COUNT(*)
FROM tblDigitalMedia tD
WHERE tD.ProductID = m.ProductID
AND tD.Active = 1)
AS ActiveDigitalFileCount
FROM dbo.main m
INNER JOIN dbo.departments d
ON m.department_id = d.department_id
INNER JOIN dbo.department_groups dg
ON d.department_group_id = dg.department_group_id
/* InventoryTemp should be called InventoryByLocation */
LEFT OUTER JOIN (SELECT
m1.ProductID,
SUM(ISNULL(it.NumberOfBoxes, 0)) + 1 AS Spaces
FROM dbo.main AS m1
INNER JOIN dbo.InventoryTemp AS it
ON m1.ProductID = it.ProductID
GROUP BY m1.ProductID) AS Boxes
ON m.ProductID = Boxes.ProductID
/* JobsTemp should be called JobHistory */
LEFT OUTER JOIN dbo.JobsTemp history
ON m.ProductID = history.ProductID
LEFT OUTER JOIN (
/* If dates are null then fetch for previous year. */
SELECT TOP (100) PERCENT
dm1.ProductID,
COUNT(dl1.TimeStamp) AS DownloadCountCustom
FROM dbo.tblDigitalMedia AS dm1
LEFT OUTER JOIN dbo.tblDigitalMediaDownloads dl1
ON dm1.FileID = dl1.FileID
WHERE ((#CustomDateStart IS NOT NULL)
AND (dl1.TimeStamp >= #CustomDateStart)
AND (dl1.TimeStamp <= #CustomDateEnd))
OR ((#CustomDateStart IS NULL)
AND (dl1.TimeStamp BETWEEN DATEADD(D, -365, GETDATE()) AND GETDATE()))
GROUP BY dm1.ProductID) AS DLsCustom
ON m.ProductID = DLsCustom.ProductID
LEFT OUTER JOIN (
/* If dates are null then fetch for previous year. */
SELECT TOP (100) PERCENT
dm2.ProductID,
COUNT(dl2.TimeStamp) AS DownloadCount
FROM dbo.tblDigitalMedia AS dm2
LEFT OUTER JOIN dbo.tblDigitalMediaDownloads dl2
ON dm2.FileID = dl2.FileID
WHERE dl2.TimeStamp BETWEEN DATEADD(D, -365, GETDATE()) AND GETDATE()
GROUP BY dm2.ProductID) AS DLs
ON m.ProductID = DLs.ProductID
LEFT OUTER JOIN dbo.tblDigitalMedia AS dm
ON m.ProductID = dm.ProductID
/* InventoryTemp should be called InventoryByLocation */
LEFT OUTER JOIN dbo.InventoryTemp it2
ON m.ProductID = it2.ProductID
INNER JOIN dbo.StoredBy sb
ON m.StoredByID = sb.StoredByID
WHERE (m.edc_isle LIKE N'Aisle' + N'%'
OR m.edc_isle = N'Digital Media'
OR m.edc_isle = N'Duplicator')
AND NOT (d.department_id BETWEEN 995 AND 999)
GROUP BY m.ProductWeight,
m.ProductID,
m.reference_number,
m.title,
m.TotalInStock,
dg.department_group_id,
m.pub_date,
m.department_id,
d.department_code,
m.pub_cost,
m.RetailPrice,
m.FullPubDate,
m.edc_isle,
sb.StoredBy,
dg.department_group,
CASE
WHEN ISNULL(dm.FileID, 0) = 0 THEN 'N/A'
ELSE 'Active'
END,
ISNULL(DLs.DownloadCount, 0),
ISNULL(DLsCustom.DownloadCountCustom, 0),
ISNULL(Boxes.Spaces, CASE
WHEN sb.StoredBy = 'WWW' THEN 0
ELSE 1
END),
m.edc_copies,
ISNULL(m.number_of_pages, 'N/A')
HAVING (NOT (MAX(sb.StoredBy) = #ShowNLA))
ORDER BY m.FullPubDate) AS BaseInventory /* ***** Table A ***** */
LEFT OUTER JOIN (SELECT
dbo.shopping_cart.ProductID,
SUM(dbo.shopping_cart.quantity) AS QuantitySold
FROM dbo.orders
INNER JOIN dbo.shopping_cart
ON dbo.orders.receiving_number = dbo.shopping_cart.receiving_number
WHERE dbo.orders.OrderTimeStamp >= DATEADD(DAY, -30, GETDATE())
AND dbo.orders.OrderTimeStamp < GETDATE()
AND dbo.shopping_cart.ProductID IS NOT NULL
GROUP BY dbo.shopping_cart.ProductID) AS Sales30Days /* ***** Table B ***** */
ON BaseInventory.ProductID = Sales30Days.ProductID
LEFT OUTER JOIN (SELECT
dbo.shopping_cart.ProductID,
SUM(dbo.shopping_cart.quantity) AS QuantitySold
FROM dbo.orders
INNER JOIN dbo.shopping_cart
ON dbo.orders.receiving_number = dbo.shopping_cart.receiving_number
WHERE #CustomDateStart IS NOT NULL
AND dbo.orders.OrderTimeStamp >= #CustomDateStart
AND dbo.orders.OrderTimeStamp <= #CustomDateEnd
AND dbo.shopping_cart.ProductID IS NOT NULL
GROUP BY dbo.shopping_cart.ProductID) AS CustomRangeSales /* ***** CustomRangeSales ***** */
ON BaseInventory.ProductID = CustomRangeSales.ProductID
LEFT OUTER JOIN (SELECT TOP (100) PERCENT
cart3.ProductID,
SUM(cart3.quantity) AS QuantitySold,
m3.TotalInStock,
CASE
WHEN
CONVERT(int, m3.TotalInStock / (CONVERT(decimal(18, 10), SUM(cart3.quantity)) / 365)) > ((9999 - YEAR(GETDATE())) * 365) THEN NULL
ELSE CONVERT(varchar, DATEADD(DAY, CONVERT(int, m3.TotalInStock / (CONVERT(decimal(18, 10), SUM(cart3.quantity)) / 365)), GETDATE()), 101)
END AS ZeroStock,
CASE
WHEN
CONVERT(int, m3.TotalInStock / (CONVERT(decimal(18, 10), SUM(cart3.quantity)) / 365)) > ((9999 - YEAR(GETDATE())) * 365) THEN NULL
ELSE DATEADD(DAY, CONVERT(int, m3.TotalInStock / (CONVERT(decimal(18, 10), SUM(cart3.quantity)) / 365)), GETDATE())
END AS ZeroStockFullDate,
CONVERT(decimal(18, 3), SUM(cart3.quantity) / ISNULL(CONVERT(decimal(18, 2), AvgInventory.NumberPerBox), SUM(cart3.quantity) + m3.TotalInStock)) AS SpacesSold,
AvgInventory.NumberPerBox
FROM dbo.orders AS o1
INNER JOIN dbo.shopping_cart AS cart3
ON o1.receiving_number = cart3.receiving_number
INNER JOIN dbo.main AS m3
ON cart3.ProductID = m3.ProductID
LEFT OUTER JOIN (SELECT TOP (100) PERCENT
ProductID,
AVG(NumberPerBox) AS NumberPerBox
FROM dbo.InventoryTemp
GROUP BY ProductID
ORDER BY ProductID) AS AvgInventory
ON m3.ProductID = AvgInventory.ProductID
WHERE (o1.OrderTimeStamp BETWEEN DATEADD(DAY, -365, GETDATE()) AND GETDATE() + 1)
GROUP BY cart3.ProductID,
m3.TotalInStock,
AvgInventory.NumberPerBox
HAVING (NOT (cart3.ProductID IS NULL))) AS SalesPastYear /* ***** Table C ***** */
ON BaseInventory.ProductID = SalesPastYear.ProductID
LEFT OUTER JOIN (SELECT
ProductID,
CASE
WHEN ((Auth.Company = '') OR
(Auth.Company IS NULL)) THEN LTRIM(ISNULL(Auth.FirstName, '') + ' ' + ISNULL(Auth.LastName, ''))
ELSE Auth.Company
END AS PrimaryAuthor
FROM dbo.Author AS Auth
INNER JOIN (SELECT
AUTHLINK.AuthorID,
AUTHLINK.Priority,
AUTHLINK.ProductID
FROM (SELECT TOP (100) PERCENT
ProductID,
MIN(ISNULL(Priority, 0)) AS Priority
FROM dbo.AuthorLink
GROUP BY ProductID
ORDER BY ProductID) AS AuthMinPrty
INNER JOIN dbo.AuthorLink AS AUTHLINK
ON (AuthMinPrty.ProductID = AUTHLINK.ProductID)
AND (ISNULL(AuthMinPrty.Priority, 0) = ISNULL(AUTHLINK.Priority, 0))) AS PrimaryAuthor
ON Auth.AuthorID = PrimaryAuthor.AuthorID) AS vwAuthor /* Table Author */
ON BaseInventory.ProductID = vwAuthor.ProductID
ORDER BY BaseInventory.ReferenceNumber
END
ELSE
BEGIN
SELECT TOP (100) PERCENT
BaseInventory.ProductID,
BaseInventory.ReferenceNumber,
BaseInventory.Title,
BaseInventory.StoredBy,
BaseInventory.TotalInStock,
BaseInventory.StockAtEDC,
BaseInventory.Cost,
BaseInventory.RetailPrice,
BaseInventory.PubDate,
BaseInventory.DepartmentCode,
vwAuthor.PrimaryAuthor,
ISNULL(Sales30Days.QuantitySold, 0) AS Last30Days,
ISNULL(SalesPastYear.QuantitySold, 0) AS Last365Days,
ISNULL(CustomRangeSales.QuantitySold, 0) AS CustomRange,
ISNULL(SalesPastYear.ZeroStock, '12/31/9999') AS ZeroStock,
ISNULL(SalesPastYear.ZeroStockFullDate, CONVERT(datetime, '12/31/9999', 102)) AS ZeroStockFullDate,
BaseInventory.FullPubDate,
BaseInventory.ProgramArea,
BaseInventory.Spaces,
BaseInventory.DigitalFileExists,
BaseInventory.DownloadCount,
BaseInventory.DownloadCountCustom,
ISNULL(SalesPastYear.SpacesSold, 0.000) AS SpacesSold,
BaseInventory.DateReceived,
BaseInventory.ProductWeight,
BaseInventory.NumberOfPages,
BaseInventory.DigitalFileCount,
BaseInventory.ActiveDigitalFileCount
FROM (SELECT TOP (100) PERCENT
m.ProductWeight,
m.ProductID,
m.reference_number AS ReferenceNumber,
m.title AS Title,
MAX(sb.StoredBy) AS StoredBy,
m.TotalInStock,
m.edc_copies AS StockAtEDC,
m.pub_cost AS Cost,
m.RetailPrice,
m.pub_date AS PubDate,
d.department_code AS DepartmentCode,
m.department_id AS DepartmentId,
dg.department_group AS ProgramArea,
m.FullPubDate,
ISNULL(Boxes.Spaces, CASE
WHEN sb.StoredBy = 'WWW' THEN 0
ELSE 1
END) AS Spaces,
CASE
WHEN ISNULL(dm.FileID, 0) = 0 THEN 'N/A'
ELSE 'Active'
END AS DigitalFileExists,
ISNULL(DLs.DownloadCount, 0) AS DownloadCount,
ISNULL(DLsCustom.DownloadCountCustom, 0) AS DownloadCountCustom,
MAX(history.DateReceived) AS DateReceived,
ISNULL(m.number_of_pages, 'N/A') AS NumberOfPages,
(SELECT
COUNT(*)
FROM tblDigitalMedia tD
WHERE tD.ProductID = m.ProductID)
AS DigitalFileCount,
(SELECT
COUNT(*)
FROM tblDigitalMedia tD
WHERE tD.ProductID = m.ProductID
AND tD.Active = 1)
AS ActiveDigitalFileCount
FROM dbo.main m
INNER JOIN dbo.departments d
ON m.department_id = d.department_id
INNER JOIN dbo.department_groups dg
ON d.department_group_id = dg.department_group_id
/* InventoryTemp should be called InventoryByLocation */
LEFT OUTER JOIN (SELECT
m1.ProductID,
SUM(ISNULL(it.NumberOfBoxes, 0)) + 1 AS Spaces
FROM dbo.main AS m1
INNER JOIN dbo.InventoryTemp AS it
ON m1.ProductID = it.ProductID
GROUP BY m1.ProductID) AS Boxes
ON m.ProductID = Boxes.ProductID
/* JobsTemp should be called JobHistory */
LEFT OUTER JOIN dbo.JobsTemp history
ON m.ProductID = history.ProductID
LEFT OUTER JOIN (
/* If dates are null then fetch for previous year. */
SELECT TOP (100) PERCENT
dm1.ProductID,
COUNT(dl1.TimeStamp) AS DownloadCountCustom
FROM dbo.tblDigitalMedia AS dm1
LEFT OUTER JOIN dbo.tblDigitalMediaDownloads dl1
ON dm1.FileID = dl1.FileID
WHERE ((#CustomDateStart IS NOT NULL)
AND (dl1.TimeStamp >= #CustomDateStart)
AND (dl1.TimeStamp <= #CustomDateEnd))
OR ((#CustomDateStart IS NULL)
AND (dl1.TimeStamp BETWEEN DATEADD(D, -365, GETDATE()) AND GETDATE()))
GROUP BY dm1.ProductID) AS DLsCustom
ON m.ProductID = DLsCustom.ProductID
LEFT OUTER JOIN (
/* If dates are null then fetch for previous year. */
SELECT TOP (100) PERCENT
dm2.ProductID,
COUNT(dl2.TimeStamp) AS DownloadCount
FROM dbo.tblDigitalMedia AS dm2
LEFT OUTER JOIN dbo.tblDigitalMediaDownloads dl2
ON dm2.FileID = dl2.FileID
WHERE dl2.TimeStamp BETWEEN DATEADD(D, -365, GETDATE()) AND GETDATE()
GROUP BY dm2.ProductID) AS DLs
ON m.ProductID = DLs.ProductID
LEFT OUTER JOIN dbo.tblDigitalMedia AS dm
ON m.ProductID = dm.ProductID
/* InventoryTemp should be called InventoryByLocation */
LEFT OUTER JOIN dbo.InventoryTemp it2
ON m.ProductID = it2.ProductID
INNER JOIN dbo.StoredBy sb
ON m.StoredByID = sb.StoredByID
WHERE (m.edc_isle LIKE N'Aisle' + N'%'
OR m.edc_isle = N'Digital Media'
OR m.edc_isle = N'Duplicator')
AND (dg.department_group_id = #ProgramAreaID)
GROUP BY m.ProductWeight,
m.ProductID,
m.reference_number,
m.title,
m.TotalInStock,
dg.department_group_id,
m.pub_date,
m.department_id,
d.department_code,
m.pub_cost,
m.RetailPrice,
m.FullPubDate,
m.edc_isle,
sb.StoredBy,
dg.department_group,
CASE
WHEN ISNULL(dm.FileID, 0) = 0 THEN 'N/A'
ELSE 'Active'
END,
ISNULL(DLs.DownloadCount, 0),
ISNULL(DLsCustom.DownloadCountCustom, 0),
ISNULL(Boxes.Spaces, CASE
WHEN sb.StoredBy = 'WWW' THEN 0
ELSE 1
END),
m.edc_copies,
ISNULL(m.number_of_pages, 'N/A')
HAVING (NOT (MAX(sb.StoredBy) = #ShowNLA))
ORDER BY m.FullPubDate) AS BaseInventory /* ***** Table A ***** */
LEFT OUTER JOIN (SELECT
dbo.shopping_cart.ProductID,
SUM(dbo.shopping_cart.quantity) AS QuantitySold
FROM dbo.orders
INNER JOIN dbo.shopping_cart
ON dbo.orders.receiving_number = dbo.shopping_cart.receiving_number
WHERE dbo.orders.OrderTimeStamp >= DATEADD(DAY, -30, GETDATE())
AND dbo.orders.OrderTimeStamp < GETDATE()
AND dbo.shopping_cart.ProductID IS NOT NULL
GROUP BY dbo.shopping_cart.ProductID) AS Sales30Days /* ***** Table B ***** */
ON BaseInventory.ProductID = Sales30Days.ProductID
LEFT OUTER JOIN (SELECT
dbo.shopping_cart.ProductID,
SUM(dbo.shopping_cart.quantity) AS QuantitySold
FROM dbo.orders
INNER JOIN dbo.shopping_cart
ON dbo.orders.receiving_number = dbo.shopping_cart.receiving_number
WHERE #CustomDateStart IS NOT NULL
AND dbo.orders.OrderTimeStamp >= #CustomDateStart
AND dbo.orders.OrderTimeStamp <= #CustomDateEnd
AND dbo.shopping_cart.ProductID IS NOT NULL
GROUP BY dbo.shopping_cart.ProductID) AS CustomRangeSales /* ***** CustomRangeSales ***** */
ON BaseInventory.ProductID = CustomRangeSales.ProductID
LEFT OUTER JOIN (SELECT TOP (100) PERCENT
cart3.ProductID,
SUM(cart3.quantity) AS QuantitySold,
m3.TotalInStock,
CASE
WHEN
CONVERT(int, m3.TotalInStock / (CONVERT(decimal(18, 10), SUM(cart3.quantity)) / 365)) > ((9999 - YEAR(GETDATE())) * 365) THEN NULL
ELSE CONVERT(varchar, DATEADD(DAY, CONVERT(int, m3.TotalInStock / (CONVERT(decimal(18, 10), SUM(cart3.quantity)) / 365)), GETDATE()), 101)
END AS ZeroStock,
CASE
WHEN
CONVERT(int, m3.TotalInStock / (CONVERT(decimal(18, 10), SUM(cart3.quantity)) / 365)) > ((9999 - YEAR(GETDATE())) * 365) THEN NULL
ELSE DATEADD(DAY, CONVERT(int, m3.TotalInStock / (CONVERT(decimal(18, 10), SUM(cart3.quantity)) / 365)), GETDATE())
END AS ZeroStockFullDate,
CONVERT(decimal(18, 3), SUM(cart3.quantity) / ISNULL(CONVERT(decimal(18, 2), AvgInventory.NumberPerBox), SUM(cart3.quantity) + m3.TotalInStock)) AS SpacesSold,
AvgInventory.NumberPerBox
FROM dbo.orders AS o1
INNER JOIN dbo.shopping_cart AS cart3
ON o1.receiving_number = cart3.receiving_number
INNER JOIN dbo.main AS m3
ON cart3.ProductID = m3.ProductID
LEFT OUTER JOIN (SELECT TOP (100) PERCENT
ProductID,
AVG(NumberPerBox) AS NumberPerBox
FROM dbo.InventoryTemp
GROUP BY ProductID
ORDER BY ProductID) AS AvgInventory
ON m3.ProductID = AvgInventory.ProductID
WHERE (o1.OrderTimeStamp BETWEEN DATEADD(DAY, -365, GETDATE()) AND GETDATE() + 1)
GROUP BY cart3.ProductID,
m3.TotalInStock,
AvgInventory.NumberPerBox
HAVING (NOT (cart3.ProductID IS NULL))) AS SalesPastYear /* ***** Table C ***** */
ON BaseInventory.ProductID = SalesPastYear.ProductID
LEFT OUTER JOIN (SELECT
ProductID,
CASE
WHEN ((Auth.Company = '') OR
(Auth.Company IS NULL)) THEN LTRIM(ISNULL(Auth.FirstName, '') + ' ' + ISNULL(Auth.LastName, ''))
ELSE Auth.Company
END AS PrimaryAuthor
FROM dbo.Author AS Auth
INNER JOIN (SELECT
AUTHLINK.AuthorID,
AUTHLINK.Priority,
AUTHLINK.ProductID
FROM (SELECT TOP (100) PERCENT
ProductID,
MIN(ISNULL(Priority, 0)) AS Priority
FROM dbo.AuthorLink
GROUP BY ProductID
ORDER BY ProductID) AS AuthMinPrty
INNER JOIN dbo.AuthorLink AS AUTHLINK
ON (AuthMinPrty.ProductID = AUTHLINK.ProductID)
AND (ISNULL(AuthMinPrty.Priority, 0) = ISNULL(AUTHLINK.Priority, 0))) AS PrimaryAuthor
ON Auth.AuthorID = PrimaryAuthor.AuthorID) AS vwAuthor /* Table Author */
ON BaseInventory.ProductID = vwAuthor.ProductID
ORDER BY BaseInventory.ReferenceNumber
END
END /* stored procedure */
GO
Ignore all the people who are telling you to do it some other way, and see whether you can tune what you have. The person who claimed this is 4 queries is incorrect. The LINQ will compose into a single SQL statement. What you need to do is to try and find out:
What the generated SQL looks like (try capturing it using SQL Server Profiler)
Why it is inefficient (again, SQL Server Profiler, or paste into SSMS and show the query plan)
Once you have done that, it may become clearer what you need to do to your LINQ to make it perform.
One thing you could try in order simplify the amount you need to look at at one time: Execute each "inner" query in isolation and see whether any of them look bad by themselves.
Related
SQLite JOIN on subquery requires column renaming
Can somebody please explain why SELECT * FROM product p INNER JOIN container_type c ON p.bkey_containertype = c.bkey AND p.deleted = c.deleted LEFT JOIN ( SELECT bkey_containertype count( * ) FROM location l WHERE l.deleted = 0 AND l.bkey_facility = 'toronto' AND l.occupied = 0 GROUP BY l.bkey_containertype ) l ON c.bkey = l.bkey_containertype WHERE p.deleted = 0 AND p.country_code = 'CA' AND p.valid_to >= date('now') AND p.valid_from <= date('now'); returns 1 row in SQLite and SELECT * FROM product p INNER JOIN container_type c ON p.bkey_containertype = c.bkey AND p.deleted = c.deleted LEFT JOIN ( SELECT bkey_containertype as bkey_containertype, count( * ) FROM location l WHERE l.deleted = 0 AND l.bkey_facility = 'toronto' AND l.occupied = 0 GROUP BY l.bkey_containertype ) l ON c.bkey = l.bkey_containertype WHERE p.deleted = 0 AND p.country_code = 'CA' AND p.valid_to >= date('now') AND p.valid_from <= date('now'); returns 3 rows (as expected)? The only difference here is in the SELECT bkey_containertype row and I have no idea why it would behave any different.
dynamic query showing 'Unclosed quotation mark after the character string '),
i have a stored procedure in which i am getting error 'Unclosed quotation mark after the character string ' having a hard time with the script. please help me to find out what is wrong in my code. here is my code. ALTER PROCEDURE [dbo].[usp_Transfer] #orgid bigint, #SearchString nvarchar (500) = null, #LocationId bigint = 0, #ownerid bigint, #OrderList varchar(MAX) AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements.\ SET NOCOUNT ON; DECLARE #SQL varchar(MAX) BEGIN SET #SQL = 'SELECT ProductID = ii.ProductId, InvItemId = convert(bigint,0),Name = p.Name, PrimaryImageID = p.PrimaryImageID,ProductNumberLabel = p.ProductNumberLabel,ProductNumber = p.ProductNumber, category = isnull(c.Name,''), qty = ISNULL((SUM(ii.[QuantityOnHand]) - SUM(ii.[QuantitySold])), 0.00), SalePrice= ISNULL(p.SalePrice, 0.00), EnteredQuantity=(case when (ISNULL((SUM(ii.[QuantityOnHand]) - SUM(ii.[QuantitySold])), 0.00) > 1) then 1.00 else ISNULL((SUM(ii.[QuantityOnHand]) - SUM(ii.[QuantitySold])), 0.00) end) ,Discount=0,u.UnitName, u.UnitID FROM dbo.[Inven] ii Left Join dbo.[Product] p on ii.ProductId = p.ProductId and p.activestatus=1 Left Join dbo.[category] c on p.DefaultCategoryId = c.CategoryId Left Join dbo.[Unit] u on p.UnitId=u.UnitId and u.Activestatus=1 WHERE p.OrganizationID = #orgid AND ii.InventoryID IN(1634) AND ii.ActiveStatus = 1 AND p.ActiveStatus = 1 AND p.IsDisabled = 0 And p.CanSale = 1 AND ii.InventoryID IN (' + #OrderList + ') group by ii.ProductId, p.Name, p.PrimaryImageID, p.ProductNumberLabel, p.ProductNumber, c.Name,p.SalePrice,u.unitname,u.UnitID having ISNULL((SUM(ii.[QuantityOnHand]) - SUM(ii.[QuantitySold])), 0) > 0 Order by p.ProductNumber, p.Name, c.Name ' --EXEC(#SQL) PRINT(#SQL) END END
Two things of note. First, does #OrderList contain any quotes? Second, this line: ...' WHERE p.OrganizationID = #orgid ' Should be: ....'WHERE p.OrganizationID = ' + #orgid + '...' The easy way to test if either of these are the cause of the problem is to comment both out, run it and see if it works, if it does then comment them in one at a time to see which one gives you the error. Finally, you could rewrite this query and avoid using a dynamic query at all. I guess looking at the query you have done it because of the IN (' + #OrderList + ') clause. These posts might help you rework that section: Parameterize an SQL IN clause SQL Server - In clause with a declared variable
Update your SP as below: Note: there are so many errors if solve one like quotation mark, declare variable #orgid and then conversion error Your initial error due to : category = isnull(c.Name,''), replace it with category = isnull(c.Name,'''') alter PROCEDURE [dbo].[usp_Transfer] #orgid bigint=1, #SearchString nvarchar (500) = null, #LocationId bigint = 0, #ownerid bigint=1, #OrderList varchar(MAX)='1' AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements.\ SET NOCOUNT ON; DECLARE #SQL varchar(MAX) BEGIN SET #SQL = 'SELECT ProductID = ii.ProductId, InvItemId = convert(bigint,0),Name = p.Name, PrimaryImageID = p.PrimaryImageID,ProductNumberLabel = p.ProductNumberLabel,ProductNumber = p.ProductNumber, category = isnull(c.Name,''''), qty = ISNULL((SUM(ii.[QuantityOnHand]) - SUM(ii.[QuantitySold])), 0.00), SalePrice= ISNULL(p.SalePrice, 0.00), EnteredQuantity=(case when (ISNULL((SUM(ii.[QuantityOnHand]) - SUM(ii.[QuantitySold])), 0.00) > 1) then 1.00 else ISNULL((SUM(ii.[QuantityOnHand]) - SUM(ii.[QuantitySold])), 0.00) end) ,Discount=0,u.UnitName, u.UnitID FROM dbo.[Inven] ii Left Join dbo.[Product] p on ii.ProductId = p.ProductId and p.activestatus=1 Left Join dbo.[category] c on p.DefaultCategoryId = c.CategoryId Left Join dbo.[Unit] u on p.UnitId=u.UnitId and u.Activestatus=1 WHERE p.OrganizationID = '+CAST(#orgid AS VARCHAR(10))+' AND ii.InventoryID IN(1634) AND ii.ActiveStatus = 1 AND p.ActiveStatus = 1 AND p.IsDisabled = 0 And p.CanSale = 1 AND ii.InventoryID IN (' + #OrderList + ') group by ii.ProductId, p.Name, p.PrimaryImageID, p.ProductNumberLabel, p.ProductNumber, c.Name,p.SalePrice,u.unitname,u.UnitID having ISNULL((SUM(ii.[QuantityOnHand]) - SUM(ii.[QuantitySold])), 0) > 0 Order by p.ProductNumber, p.Name, c.Name ' EXEC(#SQL) PRINT(#SQL) END END
MSDAX 2012 Onhand Calculation from InventSum & InventTrans tables
I have used the below query to calculate the onhand quantity from InventTrans table but that onhand does not match with the AvailPhysical and/or PhysicalInvent of InventSum table. I have tried matching with other quantities as well but onhand is not matching. Please guide me what am i missing here SELECT T1.ITEMID AS ITEMID ,T1.QTY ,T1.INVENTDIMID AS INVENTDIMID ,DATEDIFF(dd, T3.TRANSDATE, getdate()) AS Age ,t19.price as RetailPrice ,t1.CurrencyCode AS CurrencyKey ,T1.DATAAREAID AS DATAAREAID ,T1.PARTITION AS PARTITION FROM INVENTTRANS T1 LEFT JOIN INVENTTRANSORIGIN T2 ON ( T1.INVENTTRANSORIGIN = T2.RECID AND (T1.DATAAREAID = T2.DATAAREAID) AND (T1.PARTITION = T2.PARTITION) ) INNER JOIN INVENTTRANSPOSTING T3 ON ( ( ( ( T1.VOUCHERPHYSICAL = T3.VOUCHER AND (T1.DATAAREAID = T3.DATAAREAID) AND (T1.PARTITION = T3.PARTITION) ) ) AND ( T1.DATEPHYSICAL = T3.TRANSDATE AND (T1.DATAAREAID = T3.DATAAREAID) AND (T1.PARTITION = T3.PARTITION) ) ) AND ( T1.INVENTTRANSORIGIN = T3.INVENTTRANSORIGIN AND (T2.DATAAREAID = T3.DATAAREAID) AND (T2.PARTITION = T3.PARTITION) ) ) and t3.INVENTTRANSPOSTINGTYPE in (0) LEFT JOIN INVENTDIM t4 ON ( t4.inventdimid = t1.inventdimid AND t4.PARTITION = t1.PARTITION AND t4.dataareaid = t1.dataareaid ) LEFT OUTER JOIN INVENTTABLEMODULE T19 ON T19.ItemID = T1.ItemID AND T19.DataAreaID = T1.DataAreaID and T19.Partition = T1.Partition AND T19.MODULETYPE=0 LEFT OUTER JOIN INVENTTABLE T20 ON T1.ITEMID = T20.ITEMID AND T1.DATAAREAID = T20.DATAAREAID where T20.ITEMTYPE <> 2 Any help would be greatly appreciated.
Query filter assign sub query to one field value
I have stuck in this issue from the last two days. Please help. I want to assign the following query . $qr = "( select subconfigcode.field_subconfigcode_value AS configcode FROM node node LEFT JOIN field_data_field_select_parent_configuratio select_parent_configuratio ON node.nid = select_parent_configuratio.entity_id AND (select_parent_configuratio.entity_type = node AND select_parent_configuratio.deleted = 0) LEFT JOIN node select_parent_configuratio_node ON select_parent_configuratio.field_select_parent_configuratio_nid = select_parent_configuratio_node.nid LEFT JOIN field_data_field_subconfigcode subconfigcode ON select_parent_configuratio_node.nid = subconfigcode.entity_id AND (subconfigcode.entity_type = 'node' AND subconfigcode.deleted = '0') WHERE (( (select_parent_configuratio.field_select_parent_configuratio_nid = node_field_data_field_select_parent_configuratio.nid) )AND(( (node.status = '1') AND (node.type IN ('offering')) ))) ORDER BY node.created DESC, configcode ASC LIMIT 1 OFFSET 0)"; to one view's field value. I have used the following code. function general_views_query_alter(&$view, &$query) { $qr = " ( select subconfigcode.field_subconfigcode_value AS configcode FROM node node LEFT JOIN field_data_field_select_parent_configuratio select_parent_configuratio ON node.nid = select_parent_configuratio.entity_id AND (select_parent_configuratio.entity_type = node AND select_parent_configuratio.deleted = 0) LEFT JOIN node select_parent_configuratio_node ON select_parent_configuratio.field_select_parent_configuratio_nid = select_parent_configuratio_node.nid LEFT JOIN field_data_field_subconfigcode subconfigcode ON select_parent_configuratio_node.nid = subconfigcode.entity_id AND (subconfigcode.entity_type = 'node' AND subconfigcode.deleted = '0') WHERE (( (select_parent_configuratio.field_select_parent_configuratio_nid = node_field_data_field_select_parent_configuratio.nid) )AND(( (node.status = '1') AND (node.type IN ('offering')) ))) ORDER BY node.created DESC, configcode ASC LIMIT 1 OFFSET 0)"; $query->add_where(1, "node_field_data_field_select_parent_configuratio__field_data_field_subconfigcode.field_subconfigcode_value", $qr); } But, it is returning the following where query. where node_field_data_field_select_parent_configuratio__field_data_field_subconfigcode.field_subconfigcode_value = '( select subconfigcode.field_subconfigcode_value AS configcode FROM node node LEFT JOIN field_data_field_select_parent_configuratio select_parent_configuratio ON node.nid = select_parent_configuratio.entity_id AND (select_parent_configuratio.entity_type = node AND select_parent_configuratio.deleted = 0) LEFT JOIN node select_parent_configuratio_node ON select_parent_configuratio.field_select_parent_configuratio_nid = select_parent_configuratio_node.nid LEFT JOIN field_data_field_subconfigcode subconfigcode ON select_parent_configuratio_node.nid = subconfigcode.entity_id AND (subconfigcode.entity_type = \'node\' AND subconfigcode.deleted = \'0\') WHERE (( (select_parent_configuratio.field_select_parent_configuratio_nid = node_field_data_field_select_parent_configuratio.nid) )AND(( (node.status = \'1\') AND (node.type IN (\'offering\')) ))) ORDER BY node.created DESC, configcode ASC LIMIT 1 OFFSET 0) ') I want to get query without the single quote assigned for sub query and remove extra slashed added to each value. Please help.
Answer : Direct query is not applicable for assignment purpose in the add_where condition. For that, I have generated the query object using. function general_views_query_alter(&$view, &$query) { $subQuery = db_select('node', 'node'); $subQuery->leftJoin('field_data_field_select_parent_configuratio', 'select_parent_configuratio ', 'node.nid = select_parent_configuratio .entity_id'); $subQuery->condition('select_parent_configuratio.entity_type', 'node', '='); $subQuery->condition('select_parent_configuratio.deleted', '0', '='); $subQuery->leftJoin('node', 'select_parent_configuratio_node', 'select_parent_configuratio.field_select_parent_configuratio_nid = select_parent_configuratio_node.nid'); $subQuery->leftJoin('field_data_field_subconfigcode', 'subconfigcode', 'select_parent_configuratio_node.nid = subconfigcode.entity_id'); $subQuery->condition('subconfigcode.entity_type', 'node', '='); $subQuery->condition('subconfigcode.deleted', '0', '='); $subQuery->where("select_parent_configuratio.field_select_parent_configuratio_nid = node_field_data_field_select_parent_configuratio.nid"); $subQuery->condition('node.status', "1", '='); $subQuery->condition('node.type', array('offering'), 'IN'); $subQuery->orderBy('configcode'); $subQuery->addField('subconfigcode', 'field_subconfigcode_value', 'configcode'); //$subQuery->range(0, 1); $query->add_where($group,'node_field_data_field_select_parent_configuratio__field_data_field_subconfigcode.field_subconfigcode_value',$subQuery,'in'); } Using this, I am able to generate it the query and assignment to value of the variable.
Subquery with sum function to pull in multiple records
SubQuery pulling in the same record in the "ON_ORDER" column. I want the query to pull in the ON_ORDER qty per Item. Can someone please show me what I am not doing right? I have been on this for quite awhile. SELECT N.SITEID, C.LOCATION, (I.EX2AREARESP||I.EX2STDSTS||I.EX2APPTYPE) AS STD, I.ITEMNUM, I.COMMODITY, I.COMMODITYGROUP, I.DESCRIPTION, I.ISSUEUNIT, C.AVGCOST, SUM(NVL(B.CURBAL,0)) AS CURBAL, NVL(SUM(D.SHIPPEDQTY),0) AS IN_TRANSIT, ( SELECT SUM(PL.ORDERQTY - NVL(PL.RECEIVEDQTY,0)) FROM MSCRADS.PO P, MSCRADS.POLINE PL, MXRADS.ITEM I WHERE P.PONUM = PL.PONUM AND PL.LINETYPE = 'ITEM' AND P.RECEIPTS <> 'COMPLETE' AND PL.ITEMNUM = I.ITEMNUM AND P.ORDERDATE >= TO_DATE('2014/05/26','YYYY/MM/DD') AND PL.RECEIPTSCOMPLETE = '0' AND P.INTERNAL = '0' AND PL.ISSUE = '0' AND P.STATUS NOT IN ('COMPLETE','CLOSE','CAN') AND P.SITEID <> 'MS' AND P.REVISIONNUM = PL.REVISIONNUM AND (P.HISTORYFLAG = '0' OR (P.HISTORYFLAG = '1' AND P.STATUS = 'CLOSE' AND PL.RECEIVEDQTY > '0')) AND NOT (P.STATUS = 'COMPLETE' AND (PL.RECEIVEDQTY = '0' OR PL.RECEIVEDQTY IS NULL)) ) AS "ON_ORDER", NVL(SUM(CASE WHEN D.RESTYPE = 'APSOFT' THEN D.RESERVEDQTY ELSE NULL END),0) AS "ALLOCATED", NVL(SUM(CASE WHEN D.RESTYPE = 'APHARD' THEN D.RESERVEDQTY ELSE NULL END),0) AS "RESERVE", N.MINLEVEL AS ROP, N.ORDERQTY AS EOQ, N.DELIVERYTIME AS LEADTIME, NVL(N.SSTOCK,0) "SAFETY STOCK", CASE N.REORDER WHEN 1 THEN 'AUTO_RE-ORDER' WHEN 0 THEN 'MANUAL_RE-ORDER' ELSE ' ' END AS "REORDER PROCESS", N.STATUS "INVENTORY STATUS" FROM MXRADS.INVENTORY N LEFT OUTER JOIN MXRADS.ITEM I ON I.ITEMNUM = N.ITEMNUM LEFT OUTER JOIN MSCRADS.INVCOST C ON N.ITEMNUM = C.ITEMNUM AND N.LOCATION = C.LOCATION LEFT OUTER JOIN MSCRADS.INVBALANCES B ON N.ITEMNUM = B.ITEMNUM AND N.LOCATION = B.LOCATION LEFT OUTER JOIN MSCRADS.INVRESERVE D ON N.ITEMNUM = D.ITEMNUM AND N.LOCATION = D.LOCATION WHERE N.SITEID <> 'MS' AND N.LOCATION = '&WHSE' AND N.STATUS = 'ACTIVE' --AND N.ITEMNUM = '505611' GROUP BY N.SITEID, C.LOCATION, (I.EX2AREARESP||I.EX2STDSTS||I.EX2APPTYPE), I.ITEMNUM, I.COMMODITY, I.COMMODITYGROUP, I.DESCRIPTION, I.ISSUEUNIT, C.AVGCOST, N.MINLEVEL, N.ORDERQTY, N.DELIVERYTIME, N.SSTOCK, N.REORDER, N.STATUS ORDER BY 4