I am using azure sql server database. I have written one sql query to generate reprot. Here it is:
;WITH cte AS
(
SELECT ProjectID, CreatedDateUTC, ProductID, LicenseID, BackgroundID from Project p
WHERE CAST(p.CreatedDateUTC AS DATE) >= #StartDate and CAST(p.CreatedDateUTC AS DATE) <= #EndDate
and IsBackgroundUsed = 1
and s7ImageGenerated = 1 and p.SiteCode in ('b2c' )
)
SELECT ProjectID , CreatedDateUTC,
(SELECT BackgroundName from Background b WHERE b.BackgroundID = cte.BackgroundID) AS BackgroundName,
(SELECT Name FROM Product pr WHERE pr.ProductID = cte.ProductID) AS ProductName,
Case WHEN LicenseID is null THEN 'Standard' ELSE (SELECT LicenseName from License l WHERE l.LicenseID = cte.LicenseID) END AS CLA,
(SELECT PurchaseFG from Product_background pb WHERE pb.BackgroundID = cte.BackgroundID and pb.ProductId = cte.productID) AS PurchaseFG,
(SELECT FGcode from Product pr WHERE pr.ProductID = cte.ProductID) AS ProductFGCode,
--(Select dbo.[getProjectFGCodeByBackground](cte.ProductID, cte.BackgroundID)) AS FGCode,
'' AS ERPOrderNumber,
0 AS DesignQuanity
from cte
WHERE (SELECT count(*) from Approval.OrderDetail od WHERE od.ProjectID = cte.ProjectID) = 0
Is there any way to optimize this query. Timeout issue comes. I have written this query in store procedure and calling that store procedure using linq entity framework.
Earlier i have used join but it's more slow down so tried with sub query. Worked more then one year now not working.
This will definitely improve the performance, especially if the table Approval.OrderDetail is large:
...WHERE not exists
(SELECT 1 from Approval.OrderDetail od WHERE od.ProjectID = cte.ProjectID)
Writing a sub-select for every single field is a terrible way to retrieve data, as you'll likely end up with a lot of Loop Joins which have terrible performance over large data sets.
Your original JOIN method is the way to go, but you need to ensure you have appropriate indexes on your joining columns.
You can also replace the WHERE clause, with a LEFT JOIN and IS NULL combination
LEFT JOIN Approval.OrderDetail od
ON od.ProjectID = p.ProjectID
...
AND od.ProjectID IS NULL;
or a NOT EXISTS (although that is more likely to have to SCAN a wider range of rows for each row returned by the main query).
WHERE NOT EXISTS
(SELECT 1 FROM Approval.OrderDetail od WHERE od.ProjectID = cte.ProjectID)
In either case, make sure your Project table is appropriately indexed on (IsBackgroundUsed, s7ImageGenerated, SiteCode, CreatedDate) and that all joins are appropriately indexed.
I'd also question whether you actually need to cast your CreatedDateUTC fields to DATE types?
A possible simplification could be:
SELECT
p.ProjectID,
p.CreatedDateUTC,
b.BackgroundName,
pr.Name,
IIF(p.LicenseID IS NULL, 'Standard', l.LicenseName) AS CLA,
pb.PurchaseFG,
pr.FGCode AS ProductFGCode,
'' AS ERPOrderNumber,
0 AS DesignQuantity
FROM Project p
LEFT JOIN Approval.OrderDetail od
ON od.ProjectID = p.ProjectID
LEFT JOIN Background b
ON b.BackgroundID = p.BackgroundID
LEFT JOIN Product pr
ON pr.ProductID = p.ProductID
LEFT JOIN License l
ON l.LicenseID = p.LicenseID
LEFT JOIN Product_Background pb
ON pb.BackgroundID = p.BackgroundID
AND pb.ProductID = p.ProductID
WHERE p.CreatedDateUTC >= #StartDate AND p.CreatedDateUTC <= #EndDate
AND p.IsBackgroundUsed = 1
AND p.s7ImageGenerated = 1
AND p.SiteCode = 'b2c'
AND od.ProjectID IS NULL;
WHERE CAST(p.CreatedDateUTC AS DATE) >= #StartDate and CAST(p.CreatedDateUTC AS DATE) <= #EndDate
make this SARGAble ,create non clustered index on CreatedDateUTC
Suppose this is the parameter ,
declare #StartDate datetime='2018-02-01'
declare #EndDate datetime='2018-02-28'
Then,
set #EndDate=dateadd(second,-1,dateadd(day,1,#EndDate))
now you can safely use do this,
WHERE p.CreatedDateUTC >= #StartDate and p.CreatedDateUTC <= #EndDate
I think,#Mark Sinkinson query will work ok than sub query.( I will try NOT EXISTS clause once)
Use INNER JOIN if possible.
Hope you are using Store Procedure and calling the SP.
Create index on all joins columns.
Since your sub query is working fine output wise without TOP 1 so it appear that all tables have ONE to ONE relation with Project .
CREATE NONCLUSTERED INDEX IX_Project ON project (
CreatedDateUTC
,IsBackgroundUsed
,s7ImageGenerated
,SiteCode
) include (ProductID,LicenseID,BackgroundID);
Hope projectID is already Clustered Index.
Might not be much faster but easier to read for me.
You should be able to adjust #StartDate and #EndDate and not have to cast to date.
Have an index on all join and where conditions.
If those are FK you should be able to use an inner join (and should).
SELECT P.ProjectID , P.CreatedDateUTC,
b.BackgroundName,
pr.Name AS ProductName,
isnull(l.LicenseName, 'Standard') as CLA,
pb.PurchaseFG,
pr.FGcode AS ProductFGCode,
'' AS ERPOrderNumber,
0 AS DesignQuanity
from Project p
left join Background b
on b.BackgroundID = p.BackgroundID
left join Product pr
on pr.ProductID = p.ProductID
left join License l
on l.LicenseID = p.LicenseID
left join Product_background pb
on pb.BackgroundID = p.BackgroundID
and pb.ProductId = p.productID
left join Product pr
on pr.ProductID = p.ProductID
WHERE CAST(p.CreatedDateUTC AS DATE) >= #StartDate
and CAST(p.CreatedDateUTC AS DATE) <= #EndDate
and p.IsBackgroundUsed = 1
and p.s7ImageGenerated = 1
and p.SiteCode = 'b2c'
and not exists (SELECT 1
from Approval.OrderDetail od
WHERE od.ProjectID = p.ProjectID)
Related
I have SQL code that is run on SQL Server 2017 in less than 200 ms, but the same code on SQL Server 2012 takes more than 3 seconds - can anyone tell me:
why is this happening
how do I solve it
select count(*) from dbo.mConsultationQuestionsReplies = 1,300,000
This is my code:
DECLARE #maxCount int;
DECLARE #ddlIds nvarchar(max);
SET #maxCount = 6;
SET #ddlIds = '4,8,840,779,10,813,3,18,7,918';
IF OBJECT_ID('tempdb..#rList') IS NOT NULL
DROP TABLE #rList
IF OBJECT_ID('tempdb..#docList') IS NOT NULL
DROP TABLE #docList
SELECT
rd.UserID,
(CASE
WHEN ids1.value IS NULL
THEN CAST(ids2.value AS int)
ELSE CAST(ids1.value AS int)
END) [cid]
INTO
#docList
FROM
mDJDoctors [rd]
LEFT JOIN
dbo.[mDJDoctorsSpeciality] [rs] ON rd.DoctorID = rs.doctorId
LEFT JOIN
dbo.mDJSpecialtyCategory [rca] ON rca.SpecialtyId = rs.specialId
LEFT JOIN
STRING_SPLIT(#ddlIds, ',') [ids1] ON rca.CategoryId = ids1.value
LEFT JOIN
dbo.mDJDoctorsSpecialtyAbove [ars] ON ars.doctorId = rd.DoctorID
LEFT JOIN
dbo.mDJSpecialtyAboveCategory [arca] ON arca.AboveSpecialtyId = ars.SpecialtyAboveId
LEFT JOIN
STRING_SPLIT(#ddlIds, ',') [ids2] ON [arca].CategoryId = ids2.value
WHERE
[ids1].value IS NOT NULL
OR [ids2].value IS NOT NULL
SELECT *
INTO #rList
FROM
(SELECT
*,
ROW_NUMBER() OVER (PARTITION BY t.cid ORDER BY t.ReplyDateInsert DESC) AS rowNumber
FROM
(SELECT DISTINCT r.ReplyUserID, r.ReplyDateInsert, d.cid
FROM dbo.mConsultationQuestionsReplies[r]
JOIN #docList [d] ON r.ReplyUserID = d.UserID
WHERE r.ReplyId IN (SELECT MAX(r.ReplyId)[id]
FROM dbo.mConsultationQuestionsReplies[r]
JOIN #docList [d] on r.ReplyUserID = d.UserID
GROUP BY d.cid, d.UserID)) [t]) [t]
WHERE
t.rowNumber <= #maxCount
SELECT
u.FirstName AS DoctorName,
u.UserID AS DoctorUserId,
sp.specialFaName AS DoctorSpecialty,
ab.SpecialtyAboveFaName AS DoctorAboveSpecialty,
md.DoctorGUID,
md.DoctorID,
cp.ProfileISOnline,
p.ProfilePicture AS DoctorProfilePicture,
p.ProfileDateInserted,
r.ReplyDateInsert AS LastReplyDateInsert,
r.cid
FROM
dbo.mDJDoctors AS md
INNER JOIN
dbo.Core_Users AS u ON md.UserID = u.UserID
INNER JOIN
dbo.Core_Profiles AS p ON u.UserID = p.UserID
INNER JOIN
(SELECT * FROM #rList) [r] ON r.ReplyUserID = u.UserID
INNER JOIN
dbo.mConsultationDocterProfile AS cp ON cp.UserID = u.UserID
LEFT OUTER JOIN
dbo.mDJDoctorsSpeciality AS mdad ON md.DoctorID = mdad.doctorId
LEFT OUTER JOIN
dbo.mDJSpecialty AS sp ON mdad.specialId = sp.specialId
LEFT OUTER JOIN
dbo.mDJDoctorsSpecialtyAbove AS mdad2 ON md.DoctorID = mdad2.doctorId
LEFT OUTER JOIN
dbo.mDJSpecialtyAbove AS ab ON mdad2.SpecialtyAboveId = ab.SpecialtyAboveId
WHERE
cp.ProfileISOnline = 1
update :
base on guid from marc-s , i removed STRING_SPLIT and new result is
declare #maxCount int;
set #maxCount = 6;
IF OBJECT_ID('tempdb..#rList') IS NOT NULL DROP TABLE #rList
IF OBJECT_ID('tempdb..#docList') IS NOT NULL DROP TABLE #docList
select rd.UserID, (case when arca.CategoryId is null then cast(rca.CategoryId as int) else cast(arca.CategoryId as int) end)[cid] into #docList
from mDJDoctors [rd] WITH (NOLOCK)
left join dbo.[mDJDoctorsSpeciality] [rs] WITH (NOLOCK) on rd.DoctorID = rs.doctorId
left join dbo.mDJSpecialtyCategory [rca] WITH (NOLOCK) on rca.SpecialtyId = rs.specialId
left join dbo.mDJDoctorsSpecialtyAbove [ars] WITH (NOLOCK) on ars.doctorId = rd.DoctorID
left join dbo.mDJSpecialtyAboveCategory [arca] WITH (NOLOCK) on arca.AboveSpecialtyId = ars.SpecialtyAboveId
where arca.CategoryId in (4,8,840,779,10,813,3,18,7,918) or rca.CategoryId in (4,8,840,779,10,813,3,18,7,918)
select * into #rList from (
select * , ROW_NUMBER() OVER (PARTITION BY t.cid ORDER BY t.ReplyDateInsert DESC) AS rowNumber from (
select distinct r.ReplyUserID, r.ReplyDateInsert, d.cid
from dbo.mConsultationQuestionsReplies[r] WITH (NOLOCK)
join #docList [d] on r.ReplyUserID = d.UserID
where r.ReplyId in(
select max(r.ReplyId)[id]
from dbo.mConsultationQuestionsReplies[r] WITH (NOLOCK)
join #docList [d] on r.ReplyUserID = d.UserID
group by d.cid,d.UserID
))[t])[t] where t.rowNumber <= #maxCount
SELECT distinct
u.FirstName AS DoctorName,
u.UserID AS DoctorUserId,
sp.specialFaName AS DoctorSpecialty,
ab.SpecialtyAboveFaName AS DoctorAboveSpecialty,
md.DoctorGUID,
md.DoctorID,
cp.ProfileISOnline,
p.ProfilePicture AS DoctorProfilePicture,
p.ProfileDateInserted,
r.ReplyDateInsert AS LastReplyDateInsert,
r.cid
FROM dbo.mDJDoctors AS md WITH (NOLOCK)
INNER JOIN dbo.Core_Users AS u WITH (NOLOCK)
ON md.UserID = u.UserID
INNER JOIN dbo.Core_Profiles AS p WITH (NOLOCK)
ON u.UserID = p.UserID
INNER JOIN
(
select * from #rList
) [r]
ON r.ReplyUserID = u.UserID
INNER JOIN dbo.mConsultationDocterProfile AS cp WITH (NOLOCK)
ON cp.UserID = u.UserID
LEFT OUTER JOIN dbo.mDJDoctorsSpeciality AS mdad WITH (NOLOCK)
ON md.DoctorID = mdad.doctorId
LEFT OUTER JOIN dbo.mDJSpecialty AS sp WITH (NOLOCK)
ON mdad.specialId = sp.specialId
LEFT OUTER JOIN dbo.mDJDoctorsSpecialtyAbove AS mdad2 WITH (NOLOCK)
ON md.DoctorID = mdad2.doctorId
LEFT OUTER JOIN dbo.mDJSpecialtyAbove AS ab WITH (NOLOCK)
ON mdad2.SpecialtyAboveId = ab.SpecialtyAboveId
WHERE cp.ProfileISOnline = 1
order by cid, LastReplyDateInsert
its take 200 ms in sql 2017 and take 1038ms in sql 2012
update 3:
this i my execution plans xml for 2012 and 2017
2012 and 2017 execution plans
update 4:
server config
The SQL Server 2012 database is missing an index (compared to SQL Server 2017) on [dbo].[Core_Profiles]
For SQL Server 2012, there is no index on [dbo].[Core_Profiles].Userid and although the query has only 52 distinct userids, it scans the full [Core_Profiles] table (~0.5mil rows) to hash match it with 52 rows and return: 52 rows (the scale diff is considerable).
For SQL Server 2017, there is the [missing_index_9245_9243] (which also includes the ProfilePicture{?}). Instead of half million table scan, it performs a 52 rows/times loops join. There is still a keylookup to [Core_Profiles] for the retrieval of ProfileDateInserted.
The first thing to try, would be to create an index on [dbo].[Core_Profiles].Userid. Whether you choose to include the ProfilePicture is a bit irrelevant to the particular query since a key lookup is performed anyway.
A side suggestion would be to create indexes on the #temp tables. Also the retrieval of the mDJDoctorsSpeciality & mDJDoctorsSpecialtyAbove (the set of 4 table outer-joins) is used twice in the batch. Wouldn't the first execution satisfy the second(returned resultset?), so why not store it and use the #temp table instead of querying the tables again (caveat: have not looked at the query logic/model at all, only at the plans) . Most likely, the queries could be nested (inner joins), something like:
from mDJDoctors [rd] WITH (NOLOCK)
left join
(
dbo.[mDJDoctorsSpeciality] [rs] WITH (NOLOCK)
join dbo.mDJSpecialtyCategory [rca] WITH (NOLOCK) on rca.SpecialtyId = rs.specialId and rca.CategoryId in (4,8,840,779,10,813,3,18,7,918)
) on rd.DoctorID = rs.doctorId
left join
(
dbo.mDJDoctorsSpecialtyAbove [ars] WITH (NOLOCK)
join dbo.mDJSpecialtyAboveCategory [arca] WITH (NOLOCK) on arca.AboveSpecialtyId = ars.SpecialtyAboveId and arca.CategoryId in (4,8,840,779,10,813,3,18,7,918)
) on ars.doctorId = rd.DoctorID
where rs.doctorId is not null or rd.DoctorID is not null
on a second thought, isn't this a union?
(
DoctorId from dbo.mDJSpecialtyCategory....
union
DoctorId from dbo.mDJSpecialtyAboveCategory....
) as X
join mDJDoctors [rd] on DoctorId....
If I would be in your situation I would first look at the differences between the 2 instances; there are a lot of things that can impact performance of a query, just looking at the code is not enough in your case (running the same query on 2 separate instances).
So, take a look at the memory allocated to each instance, the settings (MAXDOP and CTP are a good start), are they running on the same machine? If not, are there any significant HW differences? Is there more usage (other people or applications running queries) of your SQL Server 2017 than your SQL Server 2012? Do you have the same amount of data on both servers? Are your indexes the same and are they maintained on both instances (could it be that you have a high level of fragmentation on your SQL Server 2017)? Also, take a look at the execution plans to see if they are identical on both servers.
I know it seems like a lot of questions, but without knowing the full context is hard to answer; any of the above could be the culprit for the slowness.
i need your help! I got some simple SQL skills, but this query kills me...
My Tables
Now i want the TOP5 WorkTimes on the Equipment (What Equipment got the longest WorkTime).
I want this OUTPUT:
MY Query:
SELECT
Equipment, EquipmentName, count(Equipment) as Count
FROM
Operations o
LEFT JOIN Orders ord ON ord.Id = o.[Order]
LEFT OUTER JOIN Equipments e ON ord.Equipment = e.EquipmentNumber
GROUP BY
Equipment, EquipmentName
ORDER BY Count DESC;
Another Question is how i can show o.Worktime?
i got an error with GroupBy...
please help me Thanks!
You can try this query:
select equip_nr,
(select equipmentname from table_equipments where equipmentnr = [to].equip_nr) equip_name,
sum(timeInMins) / 60.0 Worktime
from (
select (select equipmentnr from table_orders where id = [to].[order]) equip_nr,
case when workunittime = 'RH' then worktime * 60 else worktime end timeInMins
from table_operations [to]
where exists(select 1 from table_orders
where [to].[order] = id
and location = '152')
and [start] >= '2018-07-01 00:00:00.000' and [start] < '2018-08-01 00:00:00.000'
) [to] group by equip_nr
By the way, LEFT JOIN is equivalent to LEFT OUTER JOIN.
Just use SUM(worktime) as aggregate function, instead of COUNT(Equipment)
SELECT
e.[ID_Equipment]
, Name
, SUM( IIF(o.WorkUnitTime='MIN', worktime/60.0, worktime) ) as WorktimeMIN
FROM
Operations o
LEFT JOIN Orders ord ON ord.ID_Order = o.ID_Order
LEFT OUTER JOIN Equipment e ON ord.ID_Equipment = e.ID_Equipment
GROUP BY
e.[ID_Equipment]
, Name
ORDER BY
WorktimeMIN DESC
See SQL Fiddle here: http://sqlfiddle.com/#!18/5b5ed/11
I have this query that is used in a SSRS report that someone else created. The left join is the cause of the problem. If I change it to an inner join I get results (not the correct results) in about 15 seconds. With the Left Join I end up canceling the query after 20 minutes. I added an index to both Budgets.Professionals and Transactions.Professionals with no change in performance. Is there a way to rewrite the query and not use the Left Join?
SELECT
profs.ProfName as orig
,profs.Initials
,DATEPART(year, TransDate) as [Year]
,SUM(CASE WHEN IsFlatFee = 'Y' OR COALESCE(MT.Admin, 'N') = 'Y'
THEN 0.0
ELSE Units * (aph.assignedpercent/100) * isnull(B.rate, 0.0)
END) AS ctp
,SUM(CASE WHEN IsFlatFee = 'Y' OR COALESCE(MT.Admin, 'N') = 'Y'
THEN 0
ELSE Units
END * (aph.assignedpercent/100)) AS worked_hours
,SUM(Value * (aph.assignedpercent/100)) AS worked_value
, 0 AS billed_hours
,0 AS billed_value
,0 AS billed_netamt
, 0.0 as paid
, 0.0 as wo
FROM Transactions Trans
INNER JOIN Matters Matts ON Trans.matters = Matts.matters
INNER JOIN MatterTypes MT ON Matts.mattertype = MT.mattertypesdesc
and MT.Admin <> 'Y'
INNER JOIN Components Comps ON Comps.components = Trans.components
and Comps.CompType = 'F'
INNER JOIN AssignedProfsHistory APH on APH.Matters = Trans.Matters
and APH.AssignedType = 'Originating'
and Trans.TransDate between APH.EffectiveDate and
ISNULL(EndDate,'12/31/2099')
INNER JOIN Professionals profs on profs.Professionals = APH.Professionals
and profs.ProfType = 'Member'
and profs.IsActive = 'Y'
and profs.IsBillable = 'Y'
**LEFT join** (SELECT Budgets.Professionals as timekeeper, Budgets.Amount as
rate, Budgets.PeriodDate
FROM Matters Matts
INNER JOIN Budgets ON Matts.matters = Budgets.matters
and cast(Budgets.PeriodDate as Date) <= '2017-12-31'
AND MONTH('2017-12-31') = MONTH(Budgets.PeriodDate)
WHERE Matts.MatterID = '99999-99.003') as B
*on B.timekeeper = Trans.Professionals*
and YEAR(B.PeriodDate) = DATEPART(year, TransDate)
WHERE cast(transdate as DATE) between dateadd(day, 1, DATEADD(year, -3,
'2017-12-31')) and '2017-12-31'
GROUP BY profs.ProfName, profs.Initials, DATEPART(year, TransDate)
As Sean and Aaron said. There are too many things that are potentially an issue.
You seem (I'm guessing from column names) that you are joining on text columns mattertypesdesc for one. In fact most of the work is done against text columns. Even Matts.MatterID is textual. This may not be possible in your scenario but it would perform better if the tables had integer primary keys and you join on those.
Anyway, guessing aside.... You might get a quick win if you replace your sub query in the left join with a temp table.
so before you existing query just do ...
SELECT Budgets.Professionals as timekeeper, Budgets.Amount as rate, Budgets.PeriodDate
INTO #t
FROM Matters Matts
INNER JOIN Budgets ON Matts.matters = Budgets.matters
and cast(Budgets.PeriodDate as Date) <= '2017-12-31'
AND MONTH('2017-12-31') = MONTH(Budgets.PeriodDate)
WHERE Matts.MatterID = '99999-99.003'
then in your exisintg query, replace the subquery with
SELECT ...
...
...
LEFT JOIN #t as B
ON B.timekeeper = Trans.Professionals
....
You can also try with the APPLY operator... remove left join & it's on condition, use outer apply and include on conditions inside the outer apply script like
AND budgets.timekeeper = trans.professionals
AND year(budgets.perioddate) = datepart(year, transdate)
Sample
OUTER APPLY
(
SELECT budgets.professionals AS timekeeper,
budgets.amount AS rate,
budgets.perioddate
FROM matters matts
INNER JOIN budgets
ON matts.matters = budgets.matters
AND cast(budgets.perioddate AS date) <= '2017-12-31'
AND month('2017-12-31') = month(budgets.perioddate)
AND budgets.timekeeper = trans.professionals
AND year(budgets.perioddate) = datepart(year, transdate)
WHERE matts.matterid = '99999-99.003'
) AS b
Thanks everyone who responded. I took your suggestions and I was able to come up with a solution. The query that I had to kill after running for 2 hrs now finishes in about 14 seconds.
I ended up creating a cte at the beginning of the script.
;with cte as
(SELECT Transactions FROM Transactions t
WHERE cast(t.TransDate as DATE) between dateadd(day, 1, DATEADD(year, -3,
#EndDate)) and #EndDate)
Then I linked the CTE to Transactions.
FROM Transactions Trans
INNER JOIN cte ON cte.Transactions = Trans.Transactions
I then was able to remove the 'where' clause that was causing the issue.
WHERE cast(transdate as DATE) between dateadd(day, 1, DATEADD(year, -3,
#EndDate)) and #EndDate
here's a quandry I'm facing in SSRS that I'm a bit stumped on. Here's the business logic I'm trying to create.
In determining the correct # of days in lab, use the following the logic:
If a case has multiple detail items with the same BacklogGroup, Daysinlab = Max(DaysinlabGDL)
If the items are from different BackLogGroups Sum the DaysInLabGDL from each of the BackLogGroups to get the DaysInLab amount.
So for example:
Case ID Back Log Group Days Calc Days
In Lab
4595549 EMAX 5 7
4595550 EMAX 5 2
4595551 CLINICAL ZIRC 5 3
4595552 BruxZir H 5 3
4595559 Implant SS 5 4
4595559 IMPLANTCA 8 8
The Expression I'm using for Calc days is this:
=iif(Fields!CaseID.Value = Previous(Fields!CaseID.Value) and Fields!BackLogGroup.Value <> Previous(Fields!BackLogGroup.Value),Fields!ActualDaysInLab.Value + Previous(Fields!ActualDaysInLab.Value),Max(Fields!ActualDaysInLab.Value))
In essence what I'm trying to do is compare detail records within a case and if the backlog group is different for each of the detail records (there can be more than 2 detail recs/case) sum the days in lab column. If the backlog groups are the same for the detail recs then I want to take the max() of the days in lab.
If there is a case where there are say 3 detail recs and two have the same backlog group take the max of those and add them to the other.
So in the case above Calc days for caseID 4595559 should be 13 (5+8) for both detail recs. But for some reason I'm not getting that. I wound up with one being 4 and one being 8.
In case it makes a difference here's the SQL query that creates the dataset:
Declare #StartDate Datetime
Declare #EndDate Datetime
Set #StartDate = '12/01/2013'
Set #EndDate = GetDate()
SELECT
cp.CaseID
,c.DateIn
,c.DateInvoiced
,cp.ProductID
,p.BackLogGroup
,sra.SourceCategory
,sra.DaysInLabGDL
,DATEDIFF(DAY,c.DateIn,c.DateInvoiced) AS ActualDaysInLab
,dbo.GL_GetBusinessDayCount(c.DateIn,c.DateInvoiced) AS WorkingDays
FROM dbo.CaseProducts cp WITH (NOLOCK)
INNER JOIN dbo.Cases c WITH (NOLOCK)
ON cp.CaseID = c.CaseID
LEFT OUTER JOIN dbo.Products p WITH (NOLOCK)
ON cp.ProductID = p.ProductID
LEFT OUTER JOIN dbo.SalesReAllocation sra WITH (NOLOCK)
ON p.ProductID = sra.ProductID
WHERE
p.BackLogGroup IS NOT NULL
AND
c.DateInvoiced IS NOT NULL
AND
c.DateIn between #StartDate and #EndDate
Order by
cp.CaseID
I hope this is clear. If not let me know and I'll try and clarify.
Thanks in advance.
I am calling your first result set t (for convenience).
I think the solution to your problem is a double aggregation:
select CaseId, sum(DaysInLab) as DaysInLab
from (select CaseID, BackLogGroup, max(DaysInLabGDL) as DaysInLab
from t
group by CaseId, BackLogGroup
) blg
group by CaseId;
So here is the Final Query. Thanks for the help #Gordon Linoff. It put me on the right path.
Declare #StartDate Datetime
Declare #EndDate Datetime
Set #StartDate = '12/01/2013'
Set #EndDate = GetDate()
With t as
(
SELECT
--count(cp.caseID) as CaseCount
cp.CaseID
,c.DateIn
,c.DateInvoiced
,cp.ProductID
,p.BackLogGroup
,sra.SourceCategory
,sra.DaysInLabGDL
,DATEDIFF(DAY,c.DateIn,c.DateInvoiced) AS ActualDaysInLab
,dbo.GL_GetBusinessDayCount(c.DateIn,c.DateInvoiced) AS WorkingDays
FROM dbo.CaseProducts cp WITH (NOLOCK)
INNER JOIN dbo.Cases c WITH (NOLOCK)
ON cp.CaseID = c.CaseID
LEFT OUTER JOIN dbo.Products p WITH (NOLOCK)
ON cp.ProductID = p.ProductID
LEFT OUTER JOIN dbo.SalesReAllocation sra WITH (NOLOCK)
ON p.ProductID = sra.ProductID
WHERE
p.BackLogGroup IS NOT NULL
AND
c.DateInvoiced IS NOT NULL
AND
--cp.CaseID = 4595187
c.DateIn between #StartDate and #EndDate
)
select blg.CaseID, DateIn, DateInvoiced, sum(DaysInLab) as DaysInLab, blg2.BackLogGroup, blg2.Workingdays, blg2.Workingdays - sum(Daysinlab) as DaysOver
from (select CaseID, BackLogGroup, max(DaysInLabGDL) as DaysInLab, WorkingDays
from t
group by CaseId, BackLogGroup, WorkingDays
) blg
Inner Join (Select CaseID, DateIn, DateInvoiced, BackLogGroup, WorkingDays
from t
group by CaseID, DateIn, DateInvoiced, BackLogGroup, WorkingDays
) blg2 on blg.CaseID = blg2.CaseId
group by blg.CaseId, DateIn, DateInvoiced, blg2.BackLogGroup, blg2.Workingdays
having blg2.workingdays > sum(Daysinlab)
My first version of the question was confusing, I need to make smaller chunks.
If a user can filter products from a website, one product should occur only once in the list.
Because of joins this code gives me two same products, how do I solve that?
I think I need a solution without using distinct because it will give me headache later on.
code from AW2012:
declare #safetystocklevel int
set #safetystocklevel = 1000
declare #status int
set #status = 2
select * from Production.Product p
inner join Purchasing.ProductVendor pv on p.ProductID = pv.ProductID
inner join Purchasing.Vendor v on v.BusinessEntityID = pv.BusinessEntityID
inner join Production.ProductDocument pd on p.ProductID = pd.ProductID
inner join Production.Document d on d.DocumentNode = pd.DocumentNode
WHERE
(#safetystocklevel = '' or p.SafetyStockLevel = #safetystocklevel)
and (#status = '' or d.Status = #status)
output:
ProductId Name
506 Reflector
506 Reflector
Edit:
Thanks, I now use Group by to get distinct rows.
Yeah, maybe using group by works for me, Im gonna do some testing now.....
Hi again
I want all products to be searchable, so I guess I need left outer joins to achieve that.
When I add dynamic order by I get into trouble, more rows are added.
Probably because I must add poh.Status to the group by.
There are 504 rows in the product table, this query returns 776 rows.
(I have removed the filtering in WHERE since it is not interesting now, and Im joining to other tables now just to get more rows to play with)
Code:
declare #sortType nvarchar(50)
set #sortType = 'Status'
select p.ProductID,
CASE WHEN #sortType = 'Status' THEN poh.Status END as Status,
CASE WHEN #sortType = 'ProductId' THEN p.ProductID END as ProductId
from Production.Product p
left outer join Purchasing.PurchaseOrderDetail pod on p.ProductID = pod.ProductID
left outer join Purchasing.PurchaseOrderHeader poh on poh.PurchaseOrderID = pod.PurchaseOrderID
left outer join Production.ProductDocument ppd on ppd.ProductID = p.ProductID
left outer join Production.Document pd on pd.DocumentNode = ppd.DocumentNode
group by p.ProductID, poh.Status
ORDER BY
CASE WHEN #sortType = 'Status' THEN poh.Status END ASC,
CASE WHEN #sortType = 'ProductId' THEN p.ProductID END ASC
You can use Group By ProductId, Name, to select the single row, if you are not planning to include distinct. But I'll prefer "distinct" if you are not using any aggregate value in select clause.
select p.ProductId, p.Name from Production.Product p
inner join Purchasing.ProductVendor pv on p.ProductID = pv.ProductID
inner join Purchasing.Vendor v on v.BusinessEntityID = pv.BusinessEntityID
inner join Production.ProductDocument pd on p.ProductID = pd.ProductID
inner join Production.Document d on d.DocumentNode = pd.DocumentNode
WHERE
(#safetystocklevel = '' or p.SafetyStockLevel = #safetystocklevel)
and (#status = '' or d.Status = #status)
GROUP BY p.ProductId, p.Name