How to speed up a slow update query in SQL Server 2012 - sql

I have an update query that works fine, but it is way too slow and takes over 2 minutes to complete. Is there another way I can write this query to speed it up? Here is my code thanks:
UPDATE #tmpIMDS
SET
ModelFileName = b.ModelFileName,
SendEMail = b.SendEMail
FROM
(
SELECT DISTINCT
IMDSConversionReportData.ModelNumber,
ModelFileName,
'Send Email' AS SendEmail
FROM
IMDSConversionReportData,
(
SELECT DISTINCT
ModelNumber,
Max(DateAdded) AS DateAdded
FROM
IMDSConversionReportData
GROUP BY
ModelNumber) a
WHERE
IMDSConversionReportData.ModelNumber = a.ModelNumber
AND IMDSConversionReportData.DateAdded = a.DateAdded
) b
WHERE ModelID = b.ModelNumber

Instead of hitting IMDSConversionReportData table twice to get the maximum DateAdded per ModelNumber you can generate row_number to identify maximum DateAdded per ModelNumbercolumn.
Also remove distinct when you are selecting only one non aggregate column with group by which is meaningless
Try this
;WITH cte
AS (SELECT *,
'Send Email' AS SendEmail,
Row_number()OVER(partition BY ModelNumber ORDER BY DateAdded DESC) AS rn
FROM IMDSConversionReportData)
UPDATE t
SET ModelFileName = c.ModelFileName,
SendEMail = c.SendEMail
FROM #tmpIMDS t
INNER JOIN cte c
ON t.ModelID = c.ModelNumber
Where Rn = 1
Note : Always use proper INNER JOIN syntax to join two tables instead of Old style comma separated join. We always find INNER Join syntax is more readable. Keep the filters alone in Where clause

Related

SQL query is loading for long period, how it could be optimized?

This is the query:
SELECT
[Code]
FROM (
SELECT
ROW_NUMBER() OVER (PARTITION BY [OrderNo], [ProductNo] ORDER BY [Quantity] DESC) AS [RowNumber],
SUBSTRING(P.[ProductNo], 1, 2) AS [Code]
FROM [LESMESPRD].[FlexNet_prd].[dbo].[ORDER_DETAIL] AS OD
INNER JOIN [LESMESPRD].[FlexNet_prd].[dbo].[WIP_COMPONENT] AS WC ON [WC].[WiporderNo] = OD.[OrderNo]
AND WC.[WipOrderType] = OD.[OrderType]
AND WC.[Active] = 1
INNER JOIN [LESMESPRD].[FlexNet_prd].[dbo].[COMPONENT] AS C ON C.[ID] = WC.[ComponentID]
INNER JOIN [LESMESPRD].[FlexNet_prd].[dbo].[PRODUCT] AS P ON P.[ID] = C.[ProductID]
WHERE SUBSTRING(P.[ProductNo], 1, 2) IN ('43', '72')
) AS OrderBrandComponents
WHERE [RowNumber] = 1
Executing time is 1 minute and 16 seconds, maybe you can help me optimize it somehow? This query is just small piece of the code, but I found that exactly this part is slowing the process.
I tried to think that maybe problem is in sub select when I try to get my rownumber, from these tables that are linked servers data is executing in seconds, I think problem is with the functions. I hope that this query could be optimized.
I believe the delay is because your query is not sargable based on the SUBSTRING( P.[ProductNo], 1,2 ). The engine can not utilize an index on a function call. But by using the full column and using LIKE based on the first 2 characters Plus wild-card anything after, you get the same records, but able to use an index.
Now, because you are looking for 2 specific product type codes (43 and 72), I reversed the query to START with that table, then find orders the products were used. This may help optimize speed, especially if you have 100 orders with these products, but 1000s of orders otherwise. Thus, starting with a smaller set to begin with.
Also, you dont need all the square brackets all over. Typically, those are only used if you have a column name based on a "reserved" keyword, such as naming a column "from" which is an obvious keyword in a SQL statement. Or things that are known data types, function names, etc.
Finally indexes to help optimize this. I would ensure you have indexes on the following tables
table index
Product ( ProductNo, Id ) -- specifically this order
Component ( ProductID, Id
WIP_COMPONENT ( ComponentId, Active, WipOrderNo, WipOrderType )
ORDER_DETAIL ( OrderNo, OrderType )
SELECT
Code
FROM
(SELECT
ROW_NUMBER() OVER
(PARTITION BY OrderNo, ProductNo
ORDER BY Quantity DESC) AS RowNumber,
SUBSTRING(P.ProductNo, 1, 2) Code
FROM
LESMESPRD.FlexNet_prd.dbo.PRODUCT P
JOIN LESMESPRD.FlexNet_prd.dbo.COMPONENT C
ON P.ID = C.ProductID
JOIN LESMESPRD.FlexNet_prd.dbo.WIP_COMPONENT WC
ON C.ID = WC.ComponentID
AND WC.Active = 1
JOIN LESMESPRD.FlexNet_prd.dbo.ORDER_DETAIL OD
ON WC.WiporderNo = OD.OrderNo
AND WC.WipOrderType = OD.OrderType
WHERE
P.ProductNo like '43%'
OR P.ProductNo like '72%' ) AS OrderBrandComponents
WHERE
OrderBrandComponents.RowNumber = 1

Group by clause not giving expected result

I have two tables
InvoiceHead(InvoiceID,RetailerID,ExecutiveID,InvoiceDate)
InvoiceItem(InvoiceID,ItemID,Qty,Contract,Amount).
I want to get the sales qty grouped by ExecutiveId and ItemId.
I tried Following query but it doesn't give expected outcome.Grouping by both columns is not happening.As in the following screenshot the Same executive and item is not added together.they are in two rows
Screenshot of the result
SELECT
SecItem.ItemID
,SecHead.ExecutiveID
,sum(SecItem.QTY) AS Total_Qty
FROM Secondary_Sales.dbo.InvoiceHead AS SecHead
INNER JOIN Secondary_Sales.dbo.InvoiceItem AS SecItem
ON SecHead.InvoiceID = SecItem.Invoice_ID
GROUP BY
SecItem.ItemID
,SecHead.ExecutiveID
This query works in mysql and gives expected result but the same query doesn't work in msqlserver
The query as given should work, SQL Server does not implement things like this differently from MySql. I suspect this is a data issue. I suspect that the data for some of the IDs has trailing spaces. "GALSR02" does not equal "GALSR02 ". Try this query to see if that is the case:
SELECT
RTRIM(SecItem.ItemID)
,RTRIM(SecHead.ExecutiveID)
,sum(SecItem.QTY) AS Total_Qty
FROM Secondary_Sales.dbo.InvoiceHead AS SecHead
INNER JOIN Secondary_Sales.dbo.InvoiceItem AS SecItem
ON RTRIM(SecHead.InvoiceID) = RTRIM(SecItem.Invoice_ID)
GROUP BY
RTRIM(SecItem.ItemID)
,RTRIM(SecHead.ExecutiveID)
If that works then you will want to run this to correct the data and investigate how the white space got there in the first place. Once the data is corrected you can revert to your original query.
UPDATE Secondary_Sales.dbo.InvoiceHead
SET ExecutiveID = RTRIM(ExecutiveID), InvoiceID = RTRIM(InvoiceID)
UPDATE Secondary_Sales.dbo.InvoiceItem
SET ItemID = RTRIM(ItemID), Invoice_ID = RTRIM(Invoice_ID)
Try with the below query..
;with cte_1
as
(SELECT InvoiceID,ItemID,SUM(QTY) OVER (partition by ItemID order by ItemID)New_QTY
FROM InvoiceItem )
SELECT c.ItemID,h.ExecutiveID,sum(c.New_QTY) AS Total_Qty
FROM Secondary_Sales.dbo.InvoiceHead h
JOIN cte_1 c
on h.InvoiceID=c.InvoiceID
GROUP BY h.ExecutiveID,c.ItemID
if you wanted to pull the sum based on executiveId and item id, use the below query.
;with cte_1
as
(SELECT c.ItemID,h.ExecutiveID
,ROW_NUMBER() OVER(partition by h.ExecutiveID,c.ItemID order by h.ExecutiveID,c.ItemID) RNO
,SUM(QTY) OVER (partition by h.ExecutiveID,c.ItemID order by h.ExecutiveID,c.ItemID) AS Total_Qty
FROM Secondary_Sales.dbo.InvoiceHead h
JOIN econdary_Sales.dbo.InvoiceItem c
on h.InvoiceID=c.InvoiceID)
SELECT ExecutiveID,ItemID,Total_Qty
FROM cte_1
WHERE RNO=1
Try with below query hope it helps .
SELECT SecItem.ItemID,SecHead.ExecutiveID,sum(SecItem.QTY) AS Total_Qty
FROM Secondary_Sales.dbo.InvoiceHead AS SecHead
INNER JOIN Secondary_Sales.dbo.InvoiceItem AS SecItem ON SecHead.InvoiceID = SecItem.Invoice_ID
GROUP BY SecItem.ItemID,SecHead.ExecutiveID,SecItem.QTY

SQL Correlation error using OVER & PARTITION in SELECT statement

I am getting the following error when I am trying to execute my SQL SELECT statement
Could not execute statement.
Correllation name 'contact' not found
SQLCODE=-142, ODBC 3 State"42S02"
Line 1, Column 1
My code is as follows
Select forename, surname, email, quotedate
From ( SELECT *, ROW_NUMBER() OVER (PARTITION BY tblQuote.contno ORDER BY quoteno DESC) AS rn
FROM dba.quotehdr as tblQuote left join dba.contact as tblContact on tblQuote.contno = tblContact.contno)q
where rn = 1 and quotedate <=today()-720 and emailbounced = 0 and email is not null and dba.contact.statusflag = 'A'
order by quotedate desc
This error only happended when I added in
dba.contact.statusflag = 'A'
I have tried this as
tblContact.statusflag = 'A'
and I get the same error!
Any suggestions?
(What about q.statusflag = 'A' , as it seems you are using q as an Alias.) This original answer is not correct, amended to:
#Shannon Severance is correct in his comment. You are trying to use the Where clause on the outer query - which does not contain any fields from the contact table. Let me tidy your query to help you see your subquery (q) - as:
Select
forename
,surname
,email
, quotedate
From
(
SELECT
*
, ROW_NUMBER() OVER (PARTITION BY tblQuote.contno ORDER BY quoteno DESC) AS rn
FROM dba.quotehdr as tblQuote
left join dba.contact as tblContact on tblQuote.contno = tblContact.contno
) q
left join dba.contact as tblContact on q.contno = tblContact.contno
where rn = 1
and quotedate <=today()-720
and emailbounced = 0
and email is not null
and tblContact.statusflag = 'A' -- Now sourced from last left join
order by quotedate desc
You will need another LEFT JOIN on the dba.contact table to be able to access this field (ADDED NOW as an example).
Also, depending on your database engine - if your field is duplicated in both tables, the SELECT * in a subquery may eject those fields, or rename them, or throw an error. Run your inner subquery by itself and see what it produces, or use explicit field name instead of *
(I still really think your * in the subquery is causing the error and also the confusion. Remove it and replace with table.field names - this will help you understand what is going wrong ...Otherwise your query logic is pretty fine, and adding the extra left join that I suggest is overkill)

SQL Group By Clause and Empty Entries

I have a SQL Server 2005 query that I'm trying to assemble right now but I am having some difficulties.
I have a group by clause based on 5 columns: Project, Area, Name, User, Engineer.
Engineer is coming from another table and is a one to many relationship
WITH TempCTE
AS (
SELECT htce.HardwareProjectID AS ProjectId
,area.AreaId AS Area
,hs.NAME AS 'Status'
,COUNT(*) AS Amount
,MAX(htce.DateEdited) AS DateModified
,UserEditing AS LastModifiedName
,Engineer
,ROW_NUMBER() OVER (
PARTITION BY htce.HardwareProjectID
,area.AreaId
,hs.NAME
,htce.UserEditing ORDER BY htce.HardwareProjectID
,Engineer DESC
) AS row
FROM HardwareTestCase_Execution AS htce
INNER JOIN HardwareTestCase AS htc ON htce.HardwareTestCaseID = htc.HardwareTestCaseID
INNER JOIN HardwareTestGroup AS htg ON htc.HardwareTestGroupID = htg.HardwareTestGroupId
INNER JOIN Block AS b ON b.BlockId = htg.BlockId
INNER JOIN Area ON b.AreaId = Area.AreaId
INNER JOIN HardwareStatus AS hs ON htce.HardwareStatusID = hs.HardwareStatusId
INNER JOIN j_Project_Testcase AS jptc ON htce.HardwareProjectID = jptc.HardwareProjectId AND htce.HardwareTestCaseID = jptc.TestcaseId
WHERE (htce.DateEdited > #LastDateModified)
GROUP BY htce.HardwareProjectID
,area.AreaId
,hs.NAME
,htce.UserEditing
,jptc.Engineer
)
The gist of what I want is to be able to deal with empty Engineer columns. I don't want this column to have a blank second entry (where row=2).
What I want to do:
Group the items with "row" value of 1 & 2 together.
Select the Engineer that isn't empty.
Do not deselect engineers where there is not a matching row=2.
I've tried a series of joins to try and make things work. No luck so far.
Use j_Project_Testcase PIVOT( MAX(Engineer) for Row in ( [1], [2] ) then select ISNULL( [1],[2]) to select the Engineer value
I can give you a more robust example if you set up a SQL fiddle
Try reading this: PIVOT and UNPIVOT

How to increment a column based on two tables that are joined

I am trying to increment a column on a sql server table based on the join between the initial table and the joined table. The idea is to update tblForm10Objectives, set the ObjectiveNumber column to an increment number starting with 1 based on the number of rows returned from the join of tblForm10GoalsObjectives and tblForm10Objectives where ID_Form10Goal equals a number. Example query so far:
Update tblForm10Objectives
Set ObjectiveNumber = rn
From (
Select ROW_NUMBER() over (PARTITION by OG.ID_Form10Goal) as rn
, *
From (
Select *
From tblForm10GoalsObjectives OG
Join tblForm10Objectives O On OG.ID_Form10Objective = O.ID_Form10Objective
Where OG.ID_Form10Goal = 4
Order by O.ID_Form10Objective
) as tblForm10Objectives;
If the select portion of the query is performed the columns are displayed so you can see the ObjectiveNumber is currently 0 where ID_Form10Goal = 4
Once the update runs I need for the ObjectiveNumber to show 1 , 2; since there are two rows for ID_Form10Goal = 4.
I had to introduce a new table to the logic of this update statement, the table name is tblForm10Goals. The objectives need to be pulled by ID_Agency instead of ID_Form10Goal I am getting an error message stating a "a multipart identifier 'dbo.tblForm10Objectives.ID_Form10Objective = rns.ID_Form10Objective' could not be bound. I am using the following SQL Update statement:
UPDATE dbo.tblForm10Objectives
SET ObjectiveNumber = rn
FROM tblForm10Goals As g
Left Join tblForm10GoalsObjectives gobs ON g.ID_Form10Goal = gobs.ID_Form10Goal
Right Join
(
SELECT
ROW_NUMBER() OVER (PARTITION BY g.ID_Agency
ORDER BY OB.ID_Form10Objective) AS rn,
OB.ID_Form10Objective
FROM tblForm10Goals g
LEFT JOIN dbo.tblForm10GoalsObjectives gobs ON g.ID_Form10Goal = gobs.ID_Form10Goal
RIGHT JOIN dbo.tblForm10Objectives OB ON gobs.ID_Form10Objective = OB.ID_Form10Objective
Where g.ID_Agency = 2
) rns ON dbo.tblForm10Objectives.ID_Form10Object = rns.ID_Form10Objective
Your example seems to be missing a closing parenthesis somewhere, and without the table structures to look at, I can't be certain of my answer. It seems you have two tables:
tblForm10Objectives
-------------------
ID_Form10Objective
ObjectiveNumber
...
and
tblForm10GoalsObjectives
------------------------
ID_Form10Goal
ID_Form10Objective
...
If this is the case, the following query should give you the results you desire:
UPDATE dbo.tblForm10Objectives
SET ObjectiveNumber = rn
FROM dbo.tblForm10Objectives INNER JOIN
(
SELECT
ROW_NUMBER() OVER (PARTITION BY OG.ID_Form10Goal
ORDER BY O.ID_Form10Objective) AS rn,
O.ID_Form10Objective
FROM dbo.tblForm10Objectives O INNER JOIN
dbo.tblForm10GoalsObjectives OG ON OG.ID_Form10Objective = O.ID_Form10Objective
Where OG.ID_Form10Goal = 4
) rns ON dbo.tblForm10Objectives.ID_Form10Objective = rns.ID_Form10Objective
If you run the inner SELECT statement, you will see the desired ObjectiveNumber values and the corresponding ID_Form10Objective that will get updated with those values.
If you post your table structures, I or someone else may be able to be of more help.