EDIT: Just so folks understand, I'm not worried about the formatting, I'm worried about the usage of the GROUP By and the usage of the aggregate fields when it doesn't make a whole lot of sense.
I've been tasked with making some SQL more readable. While I generally know what to do, this particular query escapes me. The gist of the query involves the writer grouping by a whole bunch of fields, and adding those fields to the query results. For fields that he/she doesn't GROUP BY, they use a MIN aggregate function I guess to "make the error go away"
MIN(ISNULL(dbo.V_CONNECT_ContactPartnerDetail_0010.SAPNr, N'')) AS sapkunr,
My difficulty comes from the fact that I can stuff the GROUP BY into a CTE, and then branch out from there, but I've never gotten the row counts to match up between the query I've created and the original one. Any help on making this SQL more readable and making its intent more clear (no functions to make the error go away) would be greatly appreciated.
SELECT dbo.V_CONNECT_ContactPartnerDetail_0010.ID_FI AS firmencode,
dbo.V_CONNECT_ContactPartnerDetail_0010.ID_KP AS partnercode,
dbo.V_CONNECT_ContactPartnerDetail_0010.Nachname,
Min(Isnull(dbo.V_CONNECT_ContactPartnerDetail_0010.Vorname, '')) AS vname,
Min(CASE V_CONNECT_ContactPartnerDetail_0010.Anrede
WHEN 'Frau' THEN 2
ELSE 1
END) AS anrede,
Min(Isnull(dbo.V_CONNECT_ContactPartnerDetail_0010.EMail, N'')) AS mail,
Min(Isnull(dbo.V_CONNECT_ContactPartnerDetail_0010.SAPNr, N'')) AS sapkunr,
Isnull(dbo.V_CONNECT_ContactPartnerDetail_0010.Titel, N'') AS titel
FROM dbo.V_CONNECT_ContactPartnerDetail_0010
INNER JOIN dbo.V_CONNECT_ContactPartnerPivot
ON dbo.V_CONNECT_ContactPartnerDetail_0010.ID_C005 = dbo.V_CONNECT_ContactPartnerPivot.ID_C005
LEFT OUTER JOIN dbo.V_CONNECT_Firmen_PZ_Download
ON dbo.V_CONNECT_ContactPartnerDetail_0010.ID_VF = dbo.V_CONNECT_Firmen_PZ_Download.ID_VF
WHERE ( dbo.V_CONNECT_ContactPartnerDetail_0010.VKO = '0010' )
GROUP BY dbo.V_CONNECT_ContactPartnerDetail_0010.ID_FI,
dbo.V_CONNECT_ContactPartnerDetail_0010.ID_KP,
dbo.V_CONNECT_ContactPartnerDetail_0010.Nachname,
dbo.V_CONNECT_ContactPartnerDetail_0010.Ort,
dbo.V_CONNECT_ContactPartnerPivot.flg_spl,
dbo.V_CONNECT_ContactPartnerPivot.flg_ha,
dbo.V_CONNECT_ContactPartnerPivot.flg_fu,
dbo.V_CONNECT_ContactPartnerPivot.flg_ma,
dbo.V_CONNECT_ContactPartnerPivot.flg_ph,
Isnull(dbo.V_CONNECT_ContactPartnerDetail_0010.Titel, N'')
This is much more "readable" to me
SELECT cpd.ID_FI AS firmencode
, cpd.ID_KP AS partnercode
, cpd.Nachname AS Nachname
, MIN(ISNULL( cpd.Vorname ,'')) AS vname
, MIN(CASE cpd.Anrede WHEN 'Frau' THEN 2 ELSE 1 END) AS anrede
, MIN(ISNULL( cpd.EMail ,N'')) AS mail
, MIN(ISNULL( cpd.SAPNr ,N'')) AS sapkunr
, ISNULL( cpd.Titel ,N'') AS titel
FROM dbo.V_CONNECT_ContactPartnerDetail_0010 cpd
JOIN dbo.V_CONNECT_ContactPartnerPivot cpp
ON cpd.ID_C005 = cpp.ID_C005
LEFT
JOIN dbo.V_CONNECT_Firmen_PZ_Download fpd
ON fpd.ID_VF = cpd.ID_VF
WHERE cpd.VKO = '0010'
GROUP
BY cpd.ID_FI
, cpd.ID_KP
, cpd.Nachname
, cpd.Ort
, cpp.flg_spl
, cpp.flg_ha
, cpp.flg_fu
, cpp.flg_ma
, cpp.flg_ph
, ISNULL(cpd.Titel ,N'')
EDIT
If I was "tasked with making some SQL more readable", I'd start with the changes above.
Beyond that, it's not clear why the GROUP BY clause includes expression that aren't in the SELECT list. It's valid to do that. But what's curious is that uf there are multiple rows from "cpd" that have different values of "Ort", then there's a pontential to get multiple rows returned, with the same values of "ID_FI", "ID_KP", "Nachname".
What really sticks out though is the outer join to "fpd", and apart from the reference to the "ID_VF" column in the join condition, there aren't any references to columns from "fpd" anywhere else in the query. It seems like if that outer join were removed, we'd get the same result.
The first structural change I would propose would be the removal of the join to "fpd".
SELECT cpd.ID_FI AS firmencode
, cpd.ID_KP AS partnercode
, cpd.Nachname AS Nachname
, MIN(ISNULL( cpd.Vorname ,'')) AS vname
, MIN(CASE cpd.Anrede WHEN 'Frau' THEN 2 ELSE 1 END) AS anrede
, MIN(ISNULL( cpd.EMail ,N'')) AS mail
, MIN(ISNULL( cpd.SAPNr ,N'')) AS sapkunr
, ISNULL( cpd.Titel ,N'') AS titel
FROM dbo.V_CONNECT_ContactPartnerDetail_0010 cpd
JOIN dbo.V_CONNECT_ContactPartnerPivot cpp
ON cpp.ID_C005 = cpd.ID_C005
WHERE cpd.VKO = '0010'
GROUP
BY cpd.ID_FI
, cpd.ID_KP
, cpd.Nachname
, cpd.Ort
, ISNULL( cpd.Titel ,N'')
, cpp.flg_spl
, cpp.flg_ha
, cpp.flg_fu
, cpp.flg_ma
, cpp.flg_ph
We can rearrange the expression in the GROUP BY clause, to move "Title" up with the other columns from "cpd". Without an ORDER BY clause, there's no guarantee what order the rows will be returned in.
We can't tell (from the query, and from the information provided) whether the "ID_C005" column is the PRIMARY KEY or a UNIQUE KEY in either "cpd" or "cpp".
And not knowing that, we can't really make other change to the query without potentially changing the result. If "ID_C005" is unique in "cpp", then we could eliminate all of the "cpp" column references from the GROUP BY.
If the purpose of the inner join (to "cpp") is to filter out rows from "cpd" that don't have a matching row in "cpp", we could make some other changes to the query. And that might make it more "readable".
Related
The problem situates itself at the 4th line of the SELECT statement: CASE WHEN ct.TransactionReason=622 THEN ABS(ct.netquantity) ELSE c.RealNetWeight END AS NetWeight
When I add this line to the statement, my grouping will change. Instead of returning one line it now gives me back the amount of lines of different c.realnetweight.
Problem is that I only want to return one line. Sort of like a coalesce that when there is a ct.transactionreason = 622, it should give me ABS(ct.netquantity), otherwise the c.realnetweight. Code can be found beneath, suggestions would be very helpful. Thanks.
SELECT CASE WHEN P.Wrapped = 1 THEN T.[Level]+1 ELSE T.[Level] END AS [Level]
, #CoilId AS CoilId
, c.SupplierCoilID
, CASE WHEN ct.TransactionReason=622 THEN ABS(ct.netquantity) ELSE c.RealNetWeight END AS NetWeight
, C.RealGrossWeight
, p1.Description
, p1.product
, s.StackID
, s.ProductID
, s.Weight
, P.Product
, P.Description AS 'ProductDescription'
, COUNT(t.BlankId) AS 'NumberOfBlanks'
, c1.Description as 'Status'
, pv.ProductionWeight
, pv.BlankWeight
, t.BlankStatus
FROM #Trace T
INNER JOIN SKUTraceability SKUT ON SKUT.SKUID = T.SKUID
INNER JOIN Stack s ON SKUT.StackID = s.StackID
INNER JOIN Product p ON s.ProductID = p.ProductID
INNER JOIN Coil c ON c.CoilID=#CoilId
INNER JOIN CoilTransaction ct on ct.CoilID=#CoilId
INNER JOIN Product p1 ON c.ProductID=p1.ProductID
INNER JOIN Code c1 ON t.BlankStatus=c1.codenumber AND c1.codetypeid=17
INNER JOIN #ProductVersion pv ON pv.ProductID=p.ProductId AND s.ProductVersion = pv.ProductVersion
WHERE t.BlankId IS NOT NULL
GROUP BY T.[Level]
, c.SupplierCoilID
, CASE WHEN ct.TransactionReason=622 THEN ABS(ct.netquantity) ELSE c.RealNetWeight END
, c.RealGrossWeight
, p1.Description
, p1.product
, s.StackID
, s.ProductID
, s.Weight
, p.Product
, p.Description
, c1.Description
, pv.ProductionWeight
, pv.BlankWeight
, p.Wrapped
, t.BlankStatus
Hard to answer without understanding your table structures however, it appears that CoilTransaction is some sort of transaction table, i.e. a single product can have many transactions.
In your SELECT query, the line causing you issues, is the only line that references your CoilTransaction table therefore I believe, the reason you're returning multiple rows is because you're grouping on a value that is not unique. Also, are transactions individual items because you seem to have a quantity column on the table.
In short, you can't get the grouping you want by including those columns from your transaction table. You would need to elaborate more on what you're trying to accomplish for us to give a more suitable solution. What does that line mean?
For at least one CoilID in table Coil, you will have more than one value in the field netquantity in the table CoilTransaction. This is what is causing the increase in the number of records returned when you include this field in your CASE statement.
I would recommend finding the netquantity value that you want from CoilTransaction in a CTE, and then bringing this in to your CASE statement. For example:
;WITH transaction_summary AS (
SELECT
ct.CoilID,
ct.TransactionReason,
MAX(ct.netquantity) -- choose your aggregate function here
FROM
CoilTransaction ct
GROUP BY
ct.CoilID,
ct.TransactionReason
)
...
I have two tables (Journal and Incident). Each incident may have more than one journal entry. I want to select the record and the most recent journal data.
The where section at the bottom is what filters the incidents I want to see. Of those, I want the journal values associated with the most recent journal entry.
This is an amalgam of code I've found on here, but when I run it I get a "Query execution failed for dataset 'DataSet1'. Unfortunately, I don't have access to the log files to see if there are clues there.
Any help is appreciated. I think I may have it nested wrong.
SELECT
b.IncidentNumber
,a.Subject
,a.CreatedDateTime
,b.SubCategory
,b.EffectiveDueDate
,b.NextActionDate
,b.ProfileFullName
FROM
(
SELECT
b.IncidentNumber
,a.Subject
,a.CreatedDateTime
,rn = row_number() OVER (PARTITION by b.IncidentNumber ORDER BY
a.CreatedDateTime DESC)
,b.SubCategory
,b.EffectiveDate
,b.NextActionDate
,b.ProfileFullName
FROM
Journal a LEFT JOIN Incident b ON
a.ParentRecordNumber = b.IncidentNumber
WHERE a.Category LIKE '%KANBAN%'
AND (b.Status LIKE' %Waiting%' OR b.status LIKE '%Active%')
AND b.SubCategory <> 'User Termination'
AND b.SubCategory <> 'Res Temp Termination'
AND a.Subject LIKE 'UP |%'
) X
WHERE rn = 1
Few things:
Outer most selected values should be from inline view aliased "X" No a. or b. as those alias only are in scope to the in inner query. (except when using coorlation but that's 1 level only I believe)
You either need to right join instead of left or change the order of the tables. I believe you want all incidents and the MOST recent Journal; not all journals and the related incident if one exists. thus I changed the order.
Lastly when using outer joins, you can only put limits on the all records table of the outer join. Where clause criteria the OUTER joined tables will cause the null records generated by the outer join to be excluded. To resolve this you must move the limiting criteria to the join or use an 'or' statement to check for null (it's cleaner to move it to the join). Think of it is applying the limit before the join occurs so Null records from incident are kept. otherwise the outer join simulates a INNER JOIN by excluding those records not in both tables (or in this case in incident but not in journal)
.
SELECT x.IncidentNumber --alias x not a/b as the from is aliased as 'X'
, x.Subject
, x.CreatedDateTime
, x.SubCategory
, x.EffectiveDueDate
, x.NextActionDate
, x.ProfileFullName
FROM (SELECT b.IncidentNumber
, a.Subject
, a.CreatedDateTime
, rn = row_number() OVER (PARTITION by b.IncidentNumber
ORDER BY a.CreatedDateTime DESC)
, b.SubCategory
, b.EffectiveDate
, b.NextActionDate
, b.ProfileFullName
FROM Incident b --switched the order I think you want all incidents and if a journal exists it's value.
LEFT JOIN Journal a
ON a.ParentRecordNumber = b.IncidentNumber
-- Since A is on the if match found to B, we need to move this to the join or we lose the records created from the outer join.
AND a.Category LIKE '%KANBAN%'
AND a.Subject LIKE 'UP |%'
--moved some where clause criteria to the join Since B is on the "all records side" of the outer join we can leave B in the where clause.
WHERE (b.Status LIKE' %Waiting%' OR b.status LIKE '%Active%')
AND b.SubCategory <> 'User Termination'
AND b.SubCategory <> 'Res Temp Termination') X
WHERE rn = 1
If you are not getting records from here, then I'd start removing some of the limiting criteria to ensure the query is functioning as desired and then add back in limits to see what's causing no records to be found.
I've finally got this report working as expected. It took a few iterations to get the query working, but it's doing what it should, now. Many thanks for your assist. I would have never gotten there without it!
SELECT x.IncidentNumber
, x.Subject
, x.CreatedDateTime
, x.SubCategory
, x.ProfileFullName
, x.PropertyNumber
, x.Status
, x.EffectiveDueDate
FROM (SELECT b.IncidentNumber
, a.Subject
, a.CreatedDateTime
, rn = row_number() OVER (PARTITION by b.IncidentNumber
ORDER BY a.CreatedDateTime DESC)
, b.SubCategory
, b.ProfileFullName
, b.PropertyNumber
, b.Status
, b.EffectiveDueDate
FROM Incident b
RIGHT JOIN Journal a
ON a.ParentRecordNumber = b.IncidentNumber
AND a.Category LIKE '%KANBAN%'
AND a.Subject LIKE 'UP |%'
WHERE (b.Status LIKE' %Waiting%' OR b.status LIKE '%Active%')
) x
WHERE rn = 1
I am filtering the data of more than one table by sql select query and for that I am using left outer join in c#.net. So by excuting this query filter is not working properly.
For ex : I have data whose branchid is 1 and yearid is 1. So when excute the query it works fine i.e. it shows that data only whose branch and year id is 1.
other data whose branchid is 2 and yearid is 1. So when I am excuting the query according to this filter at that time it shows branchid is 1 and yearid is 1 and also branchid is 2 and yearid is 1.
means at second time it shows whole data of branch and yearid. So at that time filter is not working.
Here is my query
SELECT DISTINCT
Client.clientname AS ClientName ,
RetailInvoice.invoiceno AS InvoiceNo ,
RetailInvoice.pono AS PoNO ,
RetailInvoice.issuedate AS IssueDate ,
RetailInvoice.duedate AS DueDate ,
RetailInvoice.discount AS Discount ,
RetailInvoice.shipping AS Shipping ,
RetailInvoice.tax AS Tax ,
RetailInvoice.vat AS Vat ,
RetailInvoice.sese AS Sese ,
RetailInvoice.paymenttype AS PaymentType ,
RetailInvoice.chequeno AS Chequeno ,
RetailInvoice.totalamt AS TotalAmt ,
RetailInvoice.description AS Description ,
RetailInvoice.paymentpaid AS PaymentPaid ,
RetailInvoice.subtotal AS Subtotal ,
RetailInvoicePayment.productid AS ProductName ,
RetailInvoicePayment.uom AS Uom ,
RetailInvoicePayment.quantity AS Quantity ,
RetailInvoicePayment.price AS Price
FROM tbl_retailinvoice RetailInvoice
LEFT OUTER JOIN tbl_retailinvoicepayment RetailInvoicePayment
ON RetailInvoice.invoiceno = RetailInvoicePayment.invoiceno
LEFT OUTER JOIN tbl_clientdetail Client
ON RetailInvoice.clientid = Client.clientid
WHERE RetailInvoice.BranchID = 1
AND RetailInvoice.YearID = 1
AND RetailInvoice.invoiceno = 1;
In your query:
FROM tbl_retailinvoice RetailInvoice
LEFT OUTER JOIN tbl_retailinvoicepayment RetailInvoicePayment
ON RetailInvoice.invoiceno = RetailInvoicePayment.invoiceno
LEFT OUTER JOIN tbl_clientdetail Client
ON RetailInvoice.clientid = Client.clientid
WHERE RetailInvoice.BranchID = 1
AND RetailInvoice.YearID = 1
AND RetailInvoice.invoiceno = 1;
All three conditions in the WHERE clause are focused on the table RetailInvoice. You say that even if you change the where condition to this:
WHERE RetailInvoice.BranchID = 2
AND RetailInvoice.YearID = 1
AND RetailInvoice.invoiceno = 1;
..that it still shows you rows where RetailInvoice.BranchID = 1. Vaguely speaking, that shouldn't be possible, since your WHERE clause would specifically dictate that only rows with a BranchID of 2 be returned. I say "vaguely speaking" because I don't have a lot of information to go on here, but in principle what you're saying seems nonsensical.
Something in the description of the problem doesn't add up to me. This problem should not be related to the LEFT JOIN, since none of the WHERE conditions point to one of the tables included by LEFT JOIN. In other words, the problem appears to be elsewhere.
FYI, LEFT JOIN simply means "Show me the information from
RetalInvoice even if there are no matching rows in the
RetailInvoicePayment or Client tables."
As opposed to an INNER JOIN, which would only show you data where a matching row was present in all three tables.
Let's say I have a table of companies:
Company
coID | coName | coCSR
The coCSR field is a numeric ID which relates to the account handler table:
AccountHandler
ahID | ahFirstName | ahLastName
I also have a table of orders:
Order
orID | orCompanyID | orDate | orValue
Now what I need to produce is output structured as follows:
Company | Account handler | No. of orders | Total of orders
Here is the query I have tried, which produces an error:
SELECT coID, coName, ahFirstName+' '+ahLastName AS CSRName, COUNT(orID) AS numOrders, SUM(orValue) AS totalRevenue
FROM Company
LEFT JOIN AccountHandler ON coCSR = ahID
LEFT JOIN Order ON coID = orCompanyID
WHERE coCSR = 8
AND orDate > getdate() - 365
ORDER BY coName ASC
The error is: Column name 'AccountHandler.ahLastName' is invalid in the ORDER BY clause because it is not contained in an aggregate function and there is no GROUP BY clause.
If I use GROUP BY coID, I get Incorrect syntax near the keyword 'WHERE'. If I change the WHERE to HAVING because of the aggregate functions, I get errors telling me to remove each of the other column names that aren't contained in either an aggregate function or the GROUP BY clause.
I have to admit, I don't yet understand the logic and syntax of anything but the most basic SQL commands, I'm just trying to apply what I've seen used before, and it's not working. Please help me to get this working. Better still, can you help me understand why it doesn't work at the moment? :)
For one thing, your query is probably missing FROM Company, but that might somehow have been lost when you were writing your post.
You seem to be aggregating data by companies. Therefore you need to group by companies. The most likely reason why your attempt at grouping failed might be because you put GROUP BY in the wrong place. I think you put it before WHERE, but in fact it should go after it (and before ORDER BY):
SELECT
c.coID,
c.coName,
a.ahFirstName + ' ' + a.ahLastName AS CSRName,
COUNT(o.orID) AS numOrders,
SUM(o.orValue) AS totalRevenue
FROM Company c
LEFT JOIN AccountHandler a ON c.coCSR = a.ahID
LEFT JOIN [Order] o ON c.coID = o.orCompanyID
WHERE c.coCSR = 8
AND o.orDate > getdate() - 365
GROUP BY ...
ORDER BY c.coName ASC
Another question is, what to group by. SQL Server requires that all non-aggregated columns be specified in GROUP BY. Therefore your GROUP BY clause should look like this:
GROUP BY
c.coID,
c.coName,
a.ahFirstName,
a.ahLastName
Note that you can't reference columns by aliases assigned to them in the SELECT clause (e.g. CSRName). But you could use the ahFirstName+' '+ahLastName expression instead of the corresponding columns, it wouldn't make any difference in this particular situation.
If you ever need to add more non-aggregated columns to this query, you'll have to add them both to SELECT and to GROUP BY. At some point this may become a bit tedious. I would suggest you try the following instead:
SELECT
c.coID,
c.coName,
a.ahFirstName + ' ' + a.ahLastName AS CSRName,
ISNULL(o.numOrders, 0) AS numOrders,
ISNULL(o.totalRevenue, 0) AS totalRevenue
FROM Company c
LEFT JOIN AccountHandler a ON c.coCSR = a.ahID
LEFT JOIN (
SELECT
orCompanyID,
COUNT(orID) AS numOrders,
SUM(orValue) AS totalRevenue
FROM [Order]
GROUP BY
orCompanyID
WHERE orDate > getdate() - 365
) o ON c.coID = o.orCompanyID
WHERE c.coCSR = 8
ORDER BY c.coName ASC
That is, aggregating is done on the Order table only. The aggregated row set is then joined to the other tables. You can now pull more attributes to the output from either Company or AccountHandler without worrying about adding them to GROUP BY because grouping is not needed at that level any more.
Can you change the query like below? You should add Max and Group By Clause
SELECT
MAX(C.coID),
C.coName,
MAX(AH.ahFirstName+' '+ AH.ahLastName ) AS CSRName,
COUNT(O.orID) AS numOrders,
SUM(O.orValue) AS totalRevenue
From Company C
LEFT JOIN AccountHandler AH ON C.coCSR = AH.ahID
LEFT JOIN Order O ON C.coID = O.orCompanyID
WHERE C.coCSR = 8 AND
O.orDate > getdate() - 365
Group by C.coName
ORDER BY C.coName ASC
My Suggestion
You should use Alias for the selected Column Names
SELECT
--<<<non aggregate section of SELECT clause
coID
, coName
, [CSRName] = CONVERT(VARCHAR(100),ahFirstName + ' ' + ahLastName)
--<<<aggregate section of SELECT clause
, [numOrders] = COUNT(orID)
, [totalRevenue] = SUM(orValue)
FROM --<<<<<<sql is not too happy without FROM
Company c
LEFT JOIN AccountHandler a
ON coCSR = ahID
LEFT JOIN Order o
ON coID = orCompanyID
WHERE coCSR = 8
AND orDate > getdate() - 365
GROUP BY
coID
, coName
, CONVERT(VARCHAR(100),ahFirstName + ' ' + ahLastName) --<<<<looks like aggregate but is just text manipulation
ORDER BY coName ASC
You have two aggregate functions ; a COUNT and a SUM ; this means that you are required to do some grouping and the general rule of thumb is GROUP BY the non aggregate section of the select clause
The really big problem in your OP is that when you JOIN two tables, whatever flavour (LEFT, RIGHT, OUTER, INNER, CROSS) it has to be in the FROM clause and needs a table specified on either side of the join
Then if joining several tables you might like to use aliases for each of the tables; I've just used single lower case letter; c/o/a. Although looking at your column names these might not be needed as all columns are uniquely named.
Hi I have a Stored Procedure
ALTER PROCEDURE [dbo].[usp_EP_GetTherapeuticalALternates]
(
#NDCNumber CHAR(11) ,
#patientid INT ,
#pbmid INT
)
AS
BEGIN
TRUNCATE TABLE TempTherapeuticAlt
INSERT INTO TempTherapeuticAlt
SELECT --PR.ProductID AS MedicationID ,
NULL AS MedicationID ,
PR.ePrescribingName AS MedicationName ,
U.Strength AS MedicationStrength ,
FRM.FormName AS MedicationForm ,
PR.DEAClassificationID AS DEASchedule ,
NULL AS NDCNumber
--INTO #myTemp
FROM DatabaseTwo.dbo.Product PR
JOIN ( SELECT MP.MarketedProductID
FROM DatabaseTwo.dbo.Therapeutic_Concept_Tree_Specific_Product TCTSP
JOIN DatabaseTwo.dbo.Marketed_Product MP ON MP.SpecificProductID = TCTSP.SpecificProductID
JOIN ( SELECT TCTSP.TherapeuticConceptTreeID
FROM DatabaseTwo.dbo.Marketed_Product MP
JOIN DatabaseTwo.dbo.Therapeutic_Concept_Tree_Specific_Product TCTSP ON MP.SpecificProductID = TCTSP.SpecificProductID
JOIN ( SELECT
PR.MarketedProductID
FROM
DatabaseTwo.dbo.Package PA
JOIN DatabaseTwo.dbo.Product PR ON PA.ProductID = PR.ProductID
WHERE
PA.NDC11 = #NDCNumber
) PAPA ON MP.MarketedProductID = PAPA.MarketedProductID
) xxx ON TCTSP.TherapeuticConceptTreeID = xxx.TherapeuticConceptTreeID
) MPI ON PR.MarketedProductID = MPI.MarketedProductID
JOIN ( SELECT P.ProductID ,
O.Strength ,
O.Unit
FROM DatabaseTwo.dbo.Product AS P
INNER JOIN DatabaseTwo.dbo.Marketed_Product
AS M ON P.MarketedProductID = M.MarketedProductID
INNER JOIN DatabaseTwo.dbo.Specific_Product
AS S ON M.SpecificProductID = S.SpecificProductID
LEFT OUTER JOIN DatabaseTwo.dbo.OrderableName_Combined
AS O ON S.SpecificProductID = O.SpecificProductID
GROUP BY P.ProductID ,
O.Strength ,
O.Unit
) U ON PR.ProductID = U.ProductID
JOIN ( SELECT PA.ProductID ,
S.ScriptFormID ,
F.Code AS NCPDPScriptFormCode ,
S.FormName
FROM DatabaseTwo.dbo.Package AS PA
INNER JOIN DatabaseTwo.dbo.Script_Form
AS S ON PA.NCPDPScriptFormCode = S.NCPDPScriptFormCode
INNER JOIN DatabaseTwo.dbo.FormCode AS F ON S.FormName = F.FormName
GROUP BY PA.ProductID ,
S.ScriptFormID ,
F.Code ,
S.FormName
) FRM ON PR.ProductID = FRM.ProductID
WHERE
( PR.OffMarketDate IS NULL )
OR ( PR.OffMarketDate = '' )
OR (PR.OffMarketDate = '1899-12-30 00:00:00.000')
OR ( PR.OffMarketDate <> '1899-12-30 00:00:00.000'
AND DATEDIFF(dd, GETDATE(),PR.OffMarketDate) > 0
)
GROUP BY PR.ePrescribingName ,
U.Strength ,
FRM.FormName ,
PR.DEAClassificationID
-- ORDER BY pr.ePrescribingName
SELECT LL.ProductID AS MedicationID ,
temp.MedicationName ,
temp.MedicationStrength ,
temp.MedicationForm ,
temp.DEASchedule ,
temp.NDCNumber ,
fs.[ReturnFormulary] AS FormularyStatus ,
copay.CopaTier ,
copay.FirstCopayTerm ,
copay.FlatCopayAmount ,
copay.PercentageCopay ,
copay.PharmacyType,
dbo.udf_EP_GetBrandGeneric(LL.ProductID) AS BrandGeneric
FROM TempTherapeuticAlt temp
OUTER APPLY ( SELECT TOP 1
ProductID
FROM DatabaseTwo.dbo.Product
WHERE ePrescribingName = temp.MedicationName
) AS LL
OUTER APPLY [dbo].[udf_EP_tbfGetFormularyStatus](#patientid,
LL.ProductID,
#pbmid) AS fs
OUTER APPLY ( SELECT TOP 1
*
FROM udf_EP_CopayDetails(LL.ProductID,
#PBMID,
fs.ReturnFormulary)
) copay
--ORDER BY LL.ProductID
TRUNCATE TABLE TempTherapeuticAlt
END
On my dev server I have data of 63k in each table
so this procedure took about 30 seconds to return result.
On my Production server, it is timing out, or taking >1 minute.
I am wondering my production server tables are full with 1400 millions of records,
can this be a reason.
if so what can be done, I have all required indexes on tables.
any help would be greatly appreciated.
thanks
Execution Plan
http://www.sendspace.com/file/hk8fao
Major Leakage
OUTER APPLY [dbo].[udf_EP_tbfGetFormularyStatus](#patientid,
LL.ProductID,
#pbmid) AS fs
Some strategies that may help:
Remove the first ORDER BY statement, those are killer on complex queries shouldn't be necessary.
Use CTEs to break the query into smaller pieces that can be individually addressed.
Reduce the nesting in the first set of JOINs
Extract the second and third set of joins (the GROUPED ones) and insert those into a temporary indexed table before joining and grouping everything.
You did not include the definition for function1 or function2 -- custom functions are often a place where performance issues can hide.
Without seeing the execution plan, it's difficult to see where the particular problems may be.
You have a query that selects data from 4 or 5 tables , some of them multiple times. It's really hard to say how to improve without deep analysis of what you are trying to achieve and what table structure actually is.
Data size is definitely an issue; I think it's quite obvious that the more data has to be processed, the longer query will take. Some general advices... Run the query directly and check execution plan. It may reveal bottlenecks. Then check if statistics is up to date. Also, review your tables, partitioning may help a lot in some cases. In addition, you can try altering tables and create clustered index not on PK (as it's done by default unless otherwise specified), but on other column[s] so your query will benefit from certain physical order of records. Note : do it only if you are absolutely sure what you are doing.
Finally, try refactoring your query. I have a feeling that there is a better way to get desired results (sorry, without understanding of table structure and expected results I cannot tell exact solution, but multiple joins of the same tables and bunch of derived tables don't look good to me)