Related
I have a subquery that is taking multiple minutes to execute. If I pull out just the initial rows that are being added up, it only takes half a second with 2,400ish rows so I don't understand why the main query doing the sum is taking so long.
What I'm trying to do is for all the transactions in a date range, for all the workers assigned to those transactions, add up the scheduled hours for each worker.
The query is returning the correct data, it's just taking FOREVER to do it.
QUERY
SELECT scheduled_hours = COALESCE(sum(hours), 0), worker_sysid
FROM (
SELECT DISTINCT
B.DateR1,
B.DateR2,
hours = ABS((B.DAteR1 - B.DateR2) / 3600),
B.worker_sysid
FROM Trans A
OUTER APPLY (
SELECT
DateR1 = MIN(TRANS_START),
DateR2 = MAX(TRANS_END),
worker_sysid
FROM Trans
JOIN trans_workers ON trans_workers.trans_sysid = Trans.SYSID
LEFT JOIN Service ON Service.SYSID = Trans.SERVICESYSID
WHERE
TRANS_START <= A.TRANS_END AND TRANS_END >= A.TRANS_START
AND TRANS_START IS NOT NULL AND TRANS_END IS NOT NULL
AND TRANS_START != '' AND TRANS_END != ''
AND Trans.CHARGEBY IN ('Hours', 'Hour')
AND (
COALESCE(Service.overnight, 0) != 1
OR
COALESCE(Service.active_overnight, 0) = 1
)
AND TRANSDATE BETWEEN 80387 AND 80400 ### These are Clarion dates
AND trans_workers.deleted_at IS NULL
GROUP BY worker_sysid
) B
) A
WHERE worker_sysid IS NOT NULL
GROUP BY worker_sysid
TABLES
Trans: SYSID (int, pk), TRANSDATE (int, clarion-formatted date), TRANS_START / TRANS_END (UNIX timestamp), SERVICESYSID (int, fk), CHARGEBY (varchar)
trans_workers: trans_sysid, worker_sysid, deleted_at
Service: SYSID (int, pk)
UPDATE
Moving the trans_workers join out of the OUTER APPLY has reduced the execution time from 1 minute down to 16 seconds, so that's an improvement.
SELECT scheduled_hours = COALESCE(sum(hours), 0), worker_sysid
FROM (
SELECT DISTINCT
B.DateR1,
B.DateR2,
hours = ABS((B.DateR1 - B.DateR2) / 3600),
worker_sysid
FROM Trans A
JOIN trans_workers ON A.SYSID = trans_workers.trans_sysid
OUTER APPLY (
SELECT
DateR1 = MIN(TRANS_START),
DateR2 = MAX(TRANS_END),
Trans.SYSID
FROM Trans
LEFT JOIN Service ON Service.SYSID = Trans.SERVICESYSID
WHERE
TRANS_START <= A.TRANS_END AND TRANS_END >= A.TRANS_START
AND TRANS_START IS NOT NULL AND TRANS_END IS NOT NULL
AND TRANS_START != '' AND TRANS_END != ''
AND Trans.CHARGEBY IN ('Hours', 'Hour')
AND COALESCE(Service.overnight, 0) != 1
AND TRANSDATE BETWEEN 80387 AND 80400
GROUP BY Trans.SYSID
) B
) A
WHERE worker_sysid IS NOT NULL
GROUP BY worker_sysid
ORDER BY worker_sysid
Thanks to https://www.sqlservercentral.com/forums/topic/consolidate-overlapping-date-periods I have a query that executes in under a second and returns what appear to be the correct hours. Only problem being I don't understand what's happening.
DECLARE #start INTEGER, #end INTEGER;
SET #start = 80401; --06/02/2021
SET #end = 80414; --19/02/2021
WITH cteTemp
AS (
SELECT
worker_sysid,
BeginDate =
CASE
WHEN ROW_NUMBER() OVER (PARTITION BY worker_sysid ORDER BY theDate) - openCnt = 0 THEN theDate
END,
EndDate =
CASE
WHEN ROW_NUMBER() OVER (PARTITION BY worker_sysid ORDER BY theDate) - closeCnt = 0 THEN theDate
END
FROM (
SELECT
worker_sysid,
theDate = DATEADD(day, 0, DATEDIFF(day, 0, (dateadd(day,[TRANSDATE]-(4),'1801-01-01')))) + DATEADD(day, 0 - DATEDIFF(day, 0, DATEADD(second, TRANS_START - DATEDIFF(S, GETDATE(), GETUTCDATE()), '1970-01-01')), DATEADD(second, TRANS_START - DATEDIFF(S, GETDATE(), GETUTCDATE()), '1970-01-01')),
closeCnt = NULL,
openCnt = (ROW_NUMBER() OVER (PARTITION BY worker_sysid ORDER BY DATEADD(day, 0, DATEDIFF(day, 0, (dateadd(day,[TRANSDATE]-(4),'1801-01-01')))) + DATEADD(day, 0 - DATEDIFF(day, 0, DATEADD(second, TRANS_START - DATEDIFF(S, GETDATE(), GETUTCDATE()), '1970-01-01')), DATEADD(second, TRANS_START - DATEDIFF(S, GETDATE(), GETUTCDATE()), '1970-01-01'))) * 2) - 1
FROM
Trans
INNER JOIN trans_workers ON trans_workers.trans_sysid = Trans.SYSID
JOIN Service ON Service.SYSID = Trans.SERVICESYSID
WHERE
worker_sysid IS NOT NULL
AND Trans.deleted_at IS NULL
AND trans_workers.deleted_at IS NULL
AND Trans.CHARGEBY IN ('Hour', 'Hours')
AND (transCancelled IS NULL OR transCancelled != 1)
AND (
COALESCE(Service.overnight, 0) = 0
)
AND TRANSDATE BETWEEN #start AND #end
UNION ALL
SELECT
worker_sysid,
theDate = DATEADD(day, 0, DATEDIFF(day, 0, (dateadd(day,[TRANSDATE]-(4),'1801-01-01')))) + DATEADD(day, 0 - DATEDIFF(day, 0, DATEADD(second, TRANS_END - DATEDIFF(S, GETDATE(), GETUTCDATE()), '1970-01-01')), DATEADD(second, TRANS_END - DATEDIFF(S, GETDATE(), GETUTCDATE()), '1970-01-01')),
closeCnt = ROW_NUMBER() OVER (PARTITION BY worker_sysid ORDER BY worker_sysid, DATEADD(day, 0, DATEDIFF(day, 0, (dateadd(day,[TRANSDATE]-(4),'1801-01-01')))) + DATEADD(day, 0 - DATEDIFF(day, 0, DATEADD(second, TRANS_END - DATEDIFF(S, GETDATE(), GETUTCDATE()), '1970-01-01')), DATEADD(second, TRANS_END - DATEDIFF(S, GETDATE(), GETUTCDATE()), '1970-01-01'))) * 2,
openCnt = NULL
FROM
Trans
JOIN trans_workers ON trans_workers.trans_sysid = Trans.SYSID
JOIN Service ON Service.SYSID = Trans.SERVICESYSID
WHERE
worker_sysid IS NOT NULL
AND Trans.deleted_at IS NULL
AND trans_workers.deleted_at IS NULL
AND Trans.CHARGEBY IN ('Hour', 'Hours')
AND (transCancelled IS NULL OR transCancelled != 1)
AND (
COALESCE(Service.overnight, 0) = 0
)
AND TRANSDATE BETWEEN #start AND #end
)
AS baseSelected
)
SELECT scheduled_hours = SUM(hours), worker_sysid
FROM (
SELECT
dt.worker_sysid,
hours = CAST(ABS(DATEDIFF(second, MIN(dt.BeginDate), MAX(dt.EndDate))) / 3600.0 AS DECIMAL(10,2))
FROM (
SELECT
worker_sysid,
BeginDate,
EndDate,
grpID =
IIF(BeginDate IS NOT NULL, ROW_NUMBER() OVER (PARTITION BY worker_sysid ORDER BY worker_sysid, BeginDate), ROW_NUMBER() OVER (PARTITION BY worker_sysid ORDER BY worker_sysid, EndDate))
FROM
cteTemp
WHERE
BeginDate IS NOT NULL OR EndDate IS NOT NULL
)
AS dt
GROUP BY dt.worker_sysid,grpID
) AS final_table
GROUP BY worker_sysid ORDER BY worker_sysid
Bonus points to myself for conversions because the DATE of each transaction is in Clarion and the TIME of each transaction is a Unix timestamp
So I have a query for a report that never finishes. I've allowed it to run for upwards of 20+ mins without completing. Here is the query:
DECLARE #start DATE, #end DATE
SET #start = '7-1-2019'
SET #end = '8-20-2019'
SELECT cg.*
,ba.std_StandardAcctNo AS bonus_acct
FROM [CustSalesTrend_Growth] cg
LEFT JOIN (
SELECT DISTINCT std_standardacctno
FROM [CustSalesTrend_Growth]
WHERE eleph_Period_Date BETWEEN #Start
AND #End
OR ideal_Period_Date BETWEEN #Start
AND #End
) ba ON ba.std_StandardAcctNo = cg.std_StandardAcctNo
AND cg.Period_Date >= #Start
AND cg.Period_Date <= #End
WHERE [Appearance_Count] <> 0
AND Period_gp <> 0
ORDER BY cg.std_StandardAcctNo
One of my first steps in diagnosing this is doing a simple select * on the view being referenced (CustSalesTrend_Growth) and it will finish running in about 30 seconds on average, pulling 12k records. Given this, I'm a little perplexed as to how the preceding query could add so much complexity to the execution, to the point that it never finishes. In my mind, the query above is relatively simple, so any ideas as to why this is happening?
EDIT: query for the view CustSalesTrend_Growth
CREATE VIEW [dbo].[CustSalesTrend_Growth]
AS
WITH basedata
AS (
SELECT DISTINCT a.order_num
,a.Period_Date
,a.year AS std_the_year
,a.Month AS std_the_month
,a.customer_alias AS std_StandardAcctNo
,b.SalesPerson_name
,isnull(ac.counter, 0) [Appearance_Count]
,isnull(b.[Year], 0) [The_Year]
,isnull(b.[Month], 0) [The_Month]
,isnull(b.Customer_Alias, 0) [CustomerName]
,sum(isnull(b.Gallons, 0)) [Gallon_Qty]
,sum(isnull(b.[Total Sale], 0)) [Total_Sale]
,sum(isnull(b.[Gross Profit], 0)) [Total_Gross_Profit]
FROM (
SELECT DISTINCT a.year
,a.month
,b.Customer_Alias
,convert(INTEGER, convert(VARCHAR(4), a.Year) + right('00' + convert(VARCHAR(2), a.month), 2)) AS order_num
,convert(DATE, convert(VARCHAR(2), a.Month) + '/01/' + convert(VARCHAR(4), a.Year)) AS Period_Date
FROM Complete_Sales_V2 a
JOIN (
SELECT DISTINCT Customer_Alias
FROM Complete_Sales_V2
) b ON 1 = 1
) a
JOIN PDI_Warehouse_2049_01.dbo.Appearance_Count ac ON a.Customer_Alias = ac.customer_alias
LEFT JOIN Complete_Sales_V2 b ON a.Customer_Alias = b.Customer_Alias
AND a.Month = b.Month
AND a.Year = b.Year
GROUP BY a.order_num
,a.Period_Date
,a.year
,a.Month
,a.Customer_Alias
,b.SalesPerson_Name
,ac.counter
,b.[Year]
,b.[Month]
,b.Customer_Alias
)
,saleslist
AS (
SELECT DISTINCT SalesPerson_Name
,Appearance_Count
,Period_Date
,std_the_month
,std_the_year
,std_StandardAcctNo
,isnull(sum(Total_Gross_Profit), 0) Period_GP
FROM basedata
GROUP BY SalesPerson_Name
,Appearance_Count
,Period_Date
,std_StandardAcctNo
,std_the_month
,std_the_year
)
,core_GP
AS (
SELECT DISTINCT a.Customer_Alias
,convert(DATE, convert(VARCHAR(2), a.month) + '/01/' + convert(VARCHAR(4), a.year)) AS Period_Date
,sum(a.[Gross Profit]) AS Period_GP
FROM Complete_Sales_V2 a
JOIN PDI_Warehouse_2049_01.dbo.appearance_count ac ON ac.customer_alias = a.Customer_Alias
GROUP BY counter
,convert(DATE, convert(VARCHAR(2), a.month) + '/01/' + convert(VARCHAR(4), a.year))
,a.Customer_Alias
)
,GroupedData
AS (
SELECT DISTINCT cgp.std_StandardAcctNo
,cgp.Period_Date
,sum(cgp.[Total_Gross_Profit]) AS Period_GP
,Appearance_Count
FROM basedata cgp
GROUP BY cgp.std_StandardAcctNo
,cgp.Period_Date
,Appearance_Count
)
,GP_Grouping
AS (
SELECT std_StandardAcctNo
,min(Period_Date) AS range_start
,max(Period_Date) AS range_end
,count(*) AS range_count
,GP_group
FROM (
SELECT std_StandardAcctNo
,Period_Date
,CASE
WHEN Period_GP = 0
THEN 0
ELSE 1
END AS GP_Group
,row_number() OVER (
PARTITION BY std_StandardAcctNo
,CASE
WHEN Period_GP = 0
THEN 0
ELSE 1
END ORDER BY Period_Date
) AS rn
,row_number() OVER (
PARTITION BY std_StandardAcctNo
,CASE
WHEN Period_GP = 0
THEN 0
ELSE 1
END ORDER BY Period_Date
) - row_number() OVER (
PARTITION BY std_StandardAcctNo ORDER BY Period_Date
) AS grp
,row_number() OVER (
PARTITION BY std_StandardAcctNo ORDER BY Period_Date
) AS grp2
FROM GroupedData
) a
GROUP BY std_StandardAcctNo
,grp
,GP_Group
)
,GP_Group2
AS (
SELECT gd.*
,max(gpg_prev.range_end) AS last_zero_group -- , gpg.range_count
FROM GroupedData gd
LEFT JOIN GP_Grouping gpg ON gd.std_StandardAcctNo = gpg.std_StandardAcctNo
AND gd.Period_Date BETWEEN gpg.range_start
AND gpg.range_end
LEFT JOIN (
SELECT *
FROM GP_Grouping
WHERE GP_Group = 0
AND range_count >= 12
) gpg_prev ON gpg_prev.std_StandardAcctNo = gd.std_StandardAcctNo
AND gpg.range_start > gpg_prev.range_end
GROUP BY gd.std_StandardAcctNo
,Period_Date
,Period_GP
,Appearance_Count
,gpg.range_count
)
,GP_Group3
AS (
SELECT gd.*
,Appearance_Cnt_Rel = CASE
WHEN gd.last_zero_group IS NULL
THEN Appearance_Count
ELSE ROW_NUMBER() OVER (
PARTITION BY gd.std_StandardAcctNo
,gd.last_zero_group ORDER BY gd.Period_Date
)
END
FROM GP_Group2 gd
)
,almost_done
AS (
SELECT DISTINCT bd.order_num
,bd.Period_Date
,bd.std_the_year
,bd.std_the_month
,bd.std_StandardAcctNo
,CASE
WHEN bd.[Appearance_Count] > 0
THEN bd.[Appearance_Count]
WHEN isnull(c.Appearance_Count, 0) > 0
THEN c.Appearance_Count + 1
WHEN isnull(d.Appearance_Count, 0) > 0
THEN d.Appearance_Count + 2
WHEN isnull(e.Appearance_Count, 0) > 0
THEN e.Appearance_Count + 3
ELSE 0
END AS Appearance_Count
,bd.[The_Year]
,bd.[The_Month]
,bd.[CustomerName]
,bd.[Gallon_Qty]
,bd.[Total_Sale]
,isnull(c.Appearance_Count, 0) AS Prev_Count
,isnull(d.Appearance_Count, 0) AS month2_Count
,isnull(e.Appearance_Count, 0) AS month3_Count
,CASE
WHEN bd.SalesPerson_Name IS NOT NULL
THEN bd.SalesPerson_Name
WHEN c.SalesPerson_Name IS NOT NULL
THEN c.SalesPerson_Name
WHEN d.SalesPerson_Name IS NOT NULL
THEN d.SalesPerson_Name
WHEN e.SalesPerson_Name IS NOT NULL
THEN e.SalesPerson_Name
ELSE 'NA'
END [SalesPerson]
,CASE
WHEN bd.[Appearance_Count] IS NULL
AND c.[Appearance_Count] IS NULL
AND d.[Appearance_Count] IS NULL
THEN e.Period_GP
ELSE 0
END [Lost_Gross_Profit]
,CASE
WHEN bd.Appearance_Count = 1
THEN bd.Total_Gross_Profit
ELSE 0
END AS 'New_Cust_GP'
,CASE
WHEN bd.Appearance_Count <= 12
THEN bd.Total_Gross_Profit
ELSE 0
END AS 'Young_Cust_GP'
,CASE
WHEN bd.Appearance_Count > 12
THEN bd.Total_Gross_Profit
ELSE 0
END AS 'Old_Cust_GP'
,ROW_NUMBER() OVER (
PARTITION BY bd.std_StandardAcctNo
,bd.std_The_Year
,bd.std_The_Month ORDER BY (bd.std_StandardAcctNo) DESC
) AS UNI_Period
,bd.Total_Gross_Profit AS SalesP_GP
,isnull(cg.Period_gp, 0) AS Period_gp
,CASE
WHEN isnull(b_prev.Period_gp, 0) > 0
THEN isnull(b_prev.Period_gp, 0)
WHEN isnull(d.Period_gp, 0) > 0
THEN isnull(d.Period_gp, 0)
WHEN isnull(e.Period_gp, 0) > 0
THEN isnull(e.Period_gp, 0)
ELSE 0
END AS Prev_Period_GP
,h.Mat_MoM_Shift
,CASE
WHEN isnull(b_prev.Period_gp, 0) > 0
THEN isnull(b_prev.Period_gp, 0)
WHEN isnull(d.Period_gp, 0) > 0
THEN isnull(d.Period_gp, 0)
WHEN isnull(e.Period_gp, 0) > 0
THEN isnull(e.Period_gp, 0)
ELSE 0
END * h.Mat_MoM_Shift AS Expected_GP
,isnull(c.Period_gp, 0) AS True_Prev_GP
,isnull(d.Period_gp, 0) AS True_2month_GP
,isnull(e.Period_gp, 0) AS True_3month_GP
,ideal_candidate = CASE
WHEN ((isnull(c.Period_gp, 0) + isnull(d.Period_gp, 0) + isnull(bd.Total_Gross_Profit, 0)) / 3 >= 800)
AND isnull(c.Period_gp, 0) >= 150
AND isnull(d.Period_gp, 0) >= 150
AND isnull(bd.Total_Gross_Profit, 0) >= 150
THEN 'Y'
ELSE 'N'
END
,eleph_candidate = CASE
WHEN ((isnull(c.Period_gp, 0) + isnull(d.Period_gp, 0) + isnull(bd.Total_Gross_Profit, 0)) / 3 >= 5000)
AND isnull(c.Period_gp, 0) >= 1000
AND isnull(d.Period_gp, 0) >= 1000
AND isnull(bd.Total_Gross_Profit, 0) >= 1000
THEN 'Y'
ELSE 'N
'
END
FROM basedata bd
LEFT JOIN core_GP b_prev ON bd.std_StandardAcctNo = b_prev.Customer_Alias
AND b_prev.Period_Date = dateadd(month, - 1, bd.Period_Date)
LEFT JOIN saleslist c ON c.std_StandardAcctNo = bd.std_StandardAcctNo
AND c.Period_Date = dateadd(month, - 1, bd.Period_Date)
AND CASE
WHEN bd.SalesPerson_Name IS NOT NULL
THEN bd.SalesPerson_Name
ELSE c.SalesPerson_Name
END = c.SalesPerson_Name
LEFT JOIN saleslist d ON d.std_StandardAcctNo = bd.std_StandardAcctNo
AND d.Period_Date = dateadd(month, - 2, bd.Period_Date)
AND CASE
WHEN bd.SalesPerson_Name IS NOT NULL
THEN bd.SalesPerson_Name
WHEN c.SalesPerson_Name IS NOT NULL
THEN c.SalesPerson_Name
ELSE d.SalesPerson_Name
END = d.SalesPerson_Name
LEFT JOIN saleslist e ON e.std_StandardAcctNo = bd.std_StandardAcctNo
AND e.Period_Date = dateadd(month, - 3, bd.Period_Date)
AND CASE
WHEN bd.SalesPerson_Name IS NOT NULL
THEN bd.SalesPerson_Name
WHEN c.SalesPerson_Name IS NOT NULL
THEN c.SalesPerson_Name
WHEN d.SalesPerson_Name IS NOT NULL
THEN d.SalesPerson_Name
ELSE e.SalesPerson_Name
END = e.SalesPerson_Name
LEFT JOIN RicoCustom.dbo.[Rico_Global_Monthly] h ON h.month = bd.std_the_month
LEFT JOIN core_GP cg ON bd.std_StandardAcctNo = cg.Customer_Alias
AND cg.Period_Date = bd.Period_Date
)
,get_ideal
AS (
SELECT DISTINCT min(ad.Period_Date) AS ideal_Period_Date
,ad.std_StandardAcctNo
,rc.last_zero_group
FROM almost_done ad
LEFT JOIN GP_Group3 rc ON rc.Period_Date = ad.Period_Date
AND rc.std_StandardAcctNo = ad.std_StandardAcctNo
AND rc.Period_GP = ad.Period_gp
WHERE ideal_candidate = 'Y'
AND (
rc.Appearance_Cnt_Rel BETWEEN 3
AND 6
)
GROUP BY ad.std_StandardAcctNo
,rc.last_zero_group
)
,get_elephant
AS (
SELECT DISTINCT min(ad.Period_Date) AS eleph_Period_Date
,ad.std_StandardAcctNo
,rc.last_zero_group
FROM almost_done ad
LEFT JOIN GP_Group3 rc ON rc.Period_Date = ad.Period_Date
AND rc.std_StandardAcctNo = ad.std_StandardAcctNo
AND rc.Period_GP = ad.Period_gp
WHERE eleph_candidate = 'Y'
AND (
rc.Appearance_Cnt_Rel BETWEEN 3
AND 36
)
GROUP BY ad.std_StandardAcctNo
,rc.last_zero_group
)
SELECT rc.Appearance_Cnt_Rel
,gi.ideal_Period_Date
,ge.eleph_Period_Date
,ad.*
FROM almost_done ad
LEFT JOIN GP_Group3 rc ON rc.Period_Date = ad.Period_Date
AND rc.std_StandardAcctNo = ad.std_StandardAcctNo
AND rc.Period_GP = ad.Period_gp
LEFT JOIN get_ideal gi ON ad.std_StandardAcctNo = gi.std_StandardAcctNo
AND ad.Period_Date = gi.ideal_Period_Date
LEFT JOIN get_elephant ge ON ad.std_StandardAcctNo = ge.std_StandardAcctNo
AND ad.Period_Date = ge.eleph_Period_Date
WHERE order_num > 201001
The indexing I have exists on the source table, Complete_Sales_V2. It is as follows:
index desc:
clustered, unique, primary key located on PRIMARY
index keys:
Customer_Alias, SalesPerson_Name, year, month, Invoice_Number
Since you say you can query the view I suggest selecting your view into a temp table prior to performing the query. This will simplify the query plan, allowing you to inspect it. And may hopefully speed it up.
I note in your original query you are filtering you main table against #Start and #End in the join condition. I don't think you want to do that. I think it should be in the where clause.
Also you can probably pre-filter the temp table so long as you can work out which records may be required (I couldn't because you compare to 3 different dates).
DECLARE #start DATE = '7-1-2019', #end DATE = '8-20-2019';
-- Best practice is to list the actual columns required
-- You may also be able to pre-filter here based on #start and #end
-- But as you compare them to 3 different columns in the query I don't know enough about your logic to know if this is possible or not
-- You can also add indexes to the temp table if they would speed things up
select *
into #cg
from [CustSalesTrend_Growth];
SELECT cg.*
, ba.std_StandardAcctNo AS bonus_acct
FROM #cg cg
LEFT JOIN (
SELECT DISTINCT std_standardacctno
FROM #cg
WHERE eleph_Period_Date BETWEEN #Start AND #End
OR ideal_Period_Date BETWEEN #Start AND #End
) ba ON ba.std_StandardAcctNo = cg.std_StandardAcctNo
WHERE [Appearance_Count] <> 0
AND Period_gp <> 0
AND cg.Period_Date >= #Start
AND cg.Period_Date <= #End
ORDER BY cg.std_StandardAcctNo;
drop table #cg;
Try this query that uses CTEs. I do not have the schema so some of my assumptions may not be correct. Please verify the query before you execute.
WITH t1 AS
(
SELECT *
FROM CustSalesTrend_Growth
WHERE Appearance_Count <> 0
AND Period_gp <> 0
AND Period_Date between #Start and #End
),
t2 AS
(
SELECT DISTINCT std_StandardAcctNo
FROM CustSalesTrend_Growth
WHERE eleph_Period_Date BETWEEN #Start AND #End
OR ideal_Period_Date BETWEEN #Start AND #End
)
select t1.*, t2.std_StandardAcctNo AS bonus_acct
FROM t1
LEFT JOIN t2 ON t2.std_StandardAcctNo = t1.std_StandardAcctNo
ORDER BY t2.std_StandardAcctNo
I am trying to add a column to this query that will calculate the percentage difference between c.PopulationForecast and c.PopulationActualMAX and/or c.PopulationActualMin. It would be nice if it was just one column but I will settle for two.
SELECT c.DepartmentName, c.DateandTime, c.ExecutionDate, c.PopulationForecast, c.PopulationActualMAX, c.PopulationActualMIN
FROM
(SELECT DepartmentName, DateandTime, ExecutionDate FROM ForecastTable WHERE DateandTime >= CAST(GETDATE() AS DATE)) d
CROSS APPLY
(SELECT *,
(SELECT MAX(ACT.PopulationActual) FROM ActualsTable ACT JOIN DepartmentTable DTD ON DTD.DepartmentTypeID = ACT.DepartmentTypeId JOIN FacilityTable FD ON FD.FacilityID = ACT.FacilityID WHERE (ACT.TargetDateTime >= DATEADD(DAY, -28, d.DateandTime)) and (DATEPART(WEEKDAY, ACT.TargetDateTime) = DATEPART(WEEKDAY, d.DateandTime)) and (CONCAT(FD.FacilityKey,'.All',DTD.DepartmentTypeKey) = DepartmentName))
as PopulationActualMAX,
(SELECT MIN(ACT.PopulationActual) FROM ActualsTable ACT JOIN DepartmentTable DTD ON DTD.DepartmentTypeID = ACT.DepartmentTypeId JOIN FacilityTable FD ON FD.FacilityID = ACT.FacilityID WHERE (ACT.TargetDateTime >= DATEADD(DAY, -28, d.DateandTime)) and (DATEPART(WEEKDAY, ACT.TargetDateTime) = DATEPART(WEEKDAY, d.DateandTime)) and (CONCAT(FD.FacilityKey,'.All',DTD.DepartmentTypeKey) = DepartmentName))
as PopulationActualMIN
FROM ForecastTable
WHERE
DepartmentName = d.DepartmentName
and DateandTime = d.DateandTime
and (
(ROUND (PopulationForecast, 0) >
(
SELECT MAX(ACT.PopulationActual)
FROM ActualsTable ACT
JOIN DepartmentTable DTD ON DTD.DepartmentTypeID = ACT.DepartmentTypeId
JOIN FacilityTable FD ON FD.FacilityID = ACT.FacilityID
WHERE (ACT.TargetDateTime >= DATEADD(DAY, -28, d.DateandTime))
and (DATEPART(WEEKDAY, ACT.TargetDateTime) = DATEPART(WEEKDAY, d.DateandTime))
and (CONCAT(FD.FacilityKey,'.All',DTD.DepartmentTypeKey) = d.DepartmentName)
)
)
or
(ROUND (PopulationForecast, 0) <
(
SELECT MIN(ACT.PopulationActual)
FROM ActualsTable ACT
JOIN DepartmentTable DTD ON DTD.DepartmentTypeID = ACT.DepartmentTypeId
JOIN FacilityTable FD ON FD.FacilityID = ACT.FacilityID
WHERE (ACT.TargetDateTime >= DATEADD(DAY, -28, d.DateandTime))
and (DATEPART(WEEKDAY, ACT.TargetDateTime) = DATEPART(WEEKDAY, d.DateandTime))
and (CONCAT(FD.FacilityKey,'.All',DTD.DepartmentTypeKey) = d.DepartmentName)
)
)
)
) c
Order By d.DepartmentName, d.DateandTime
Is there anything stopping you putting the difference in your outer select (first line)?
For example:
(c.PopulationForecast-c.PopulationActualMIN)/c.PopulationForecast ForecastVsMin
, (c.PopulationForecast-c.PopulationActualMAX)/c.PopulationForecast ForecastVsMax
From your query it looks like you already have all three fields you're looking for.
Is it possible to get CreatedDateTime and Createdby for the security role added to the user through sql query
This is query used to get the Security role
select distinct a.id as username , a.NAME Name, f.Text [Role]
from userinfo a (nolock) join securityuserrole b (nolock) on a.id=b.user_
join SECURITYUSERROLECONDITION c (nolock) on b.recid = c.securityuserrole
join [Dynamics_STG_model].[dbo].[ModelSecurityRole] e (nolock) on e.rolehandle = b.securityrole
join [Dynamics_STG_model].[dbo].[ModelElementLabel] f (nolock) on e.LABELID = f.LabelId and e.LABELMODULE = f.Module and f.Language='en_us'
Please help me regarding this.
Thanks in Advance!
I figured out the answer by myself:
Declare #StartDate datetime
Declare #EndDate datetime
Set #StartDate = '2015-07-07 01:31:38.000'
Set #EndDate = '2015-08-21 01:14:14.000'
Set #StartDate = convert(datetime, dateadd(hour, 7, #StartDate), 100)
Set #EndDate = convert(datetime, dateadd(hour, 7, #EndDate), 100)
select distinct a.NAME [User Name]
,b.USERNAME [Role Modified By]
,convert(datetime, dateadd(hour, -7, b.CREATEDDATETIME), 100) [Modified DateTime]
,case b.LOGTYPE
when 0 then 'Added'
when 1 then 'Removed'
end as Status
,d.Text Role
from USERINFO a (nolock)
join(
select (case when logtype = 0 then dbo.CONPEEK(CAST(dbo.CONPEEK(data, 16) AS varbinary(8000)), 2)
when logtype = 1 then dbo.CONPEEK(CAST(dbo.CONPEEK(data, 10) AS varbinary(8000)), 2)
end) AS UserNam
,USERNAME
,CREATEDDATETIME
,logtype
,(case when logtype = 0 then dbo.CONPEEK(CAST(dbo.CONPEEK(data, 15) AS varbinary(8000)), 2)
when logtype = 1 then dbo.CONPEEK(CAST(dbo.CONPEEK(data, 9) AS varbinary(8000)), 2)
end) as SecurityRole
from SYSDATABASELOG (nolock) where TABLE_=65492 and data !='') b
on a.id = b.UserNam
left outer join [DynamicsAX_model].[dbo].[modelsecurityrole] c (nolock) on b.SecurityRole =c.rolehandle
join [modelelementlabel] d (nolock) on c.labelid = d.labelid
and c.LABELMODULE = d.module
and d.Language='en_us'
where b.CREATEDDATETIME >= #StartDate and b.CREATEDDATETIME <=#EndDate order by [Modified DateTime] desc
Conpeek and consize are two functions we need to create from the below link download ConPeek.sql and ConSize.sql
You can try using database logging for table SecurityUserRole (System → Security user role).
I need some help summing two (or more) alias columns.
I know I need a derived table to do it, but so far I get lost with online tutorials and documentation as their examples are far too simple. they only have one table, two columns, etc.
What could be my best option here:
I need to calculate the sum of two alias columns: 'InFxO' and 'OnTxO' and my code is as follows:
ALTER PROC [dbo].[DIFOTIS]
#Mode as Varchar (5)
AS
Begin
Declare
#StartDate date,
#EndDate date
SET #StartDate=
CASE #Mode
WHEN 'MTD' THEN DATEADD(mm,DATEDIFF(mm,0,GETDATE()),0)
WHEN 'YTD' THEN DATEADD(yy,DATEDIFF(yy,0,GETDATE()),0)
WHEN 'QTD' THEN DATEADD(qq,DATEDIFF(qq,0,GETDATE()),0)
WHEN 'WTD' THEN DATEADD(wk,DATEDIFF(wk,0,GETDATE()),0)
END
Set #EndDate=
CASE #Mode
WHEN 'MTD' THEN DATEADD(mm,DATEDIFF(mm,0,GETDATE())+1,0)
WHEN 'YTD' THEN DATEADD(yy,DATEDIFF(yy,0,GETDATE())+1,0)
WHEN 'QTD' THEN DATEADD(qq,DATEDIFF(qq,0,GETDATE())+1,0)
WHEN 'WTD' THEN DATEADD(wk,DATEDIFF(wk,0,GETDATE())+1,0)
END
Select DATEPART(ISO_WEEK,d.DateOpn) AS 'Week#'
,Clients.CustCateg, Clients.ClntGroup
,d.DocumentCode as 'CORD_DocumentCode'
,CDSPDocs.DocumentCode AS 'DESP_DocumentCode'
,Count(CORDLines.Qnty) AS 'Cord_Lines'
,SUM(CORDLines.Qnty) AS 'CORD_Qty'
,Count(CDSPLines.Qnty) AS 'DESP_Lines'
,Sum(CDSPLines.Qnty) AS 'DESP_Qty'
,CDSPLines.Status, d.Status as d_status
,d.OpenDate, d.DateDue
,CDSPDocs.PostDate AS 'DESP_PostedDate'
,d.DocType, DATEDIFF(day, d.OpenDate, d.DateDue) AS 'Lead times'
--in-full
,CASE WHEN SUM(CORDLines.Qnty) = Sum(CDSPLines.Qnty) THEN '1' ELSE '0' END as InFxO
--On-Time by order according to Despatch SLAs
,CASE WHEN (Clients.ClntGroup IN ('Local Market','Local Market - Pharm','Web Sales - Local','Web Sales - Export', 'Mail Order','Mail Order - Export')) AND (Datediff(day, d.OpenDate, CDSPDocs.PostDate) - (Datediff(Week, d.OpenDate, CDSPDocs.PostDate)*2) <= 2) then '1'
WHEN (Clients.ClntGroup = 'Export Market') AND (Datediff(day, d.OpenDate, CDSPDocs.PostDate) - (Datediff(Week, d.OpenDate, CDSPDocs.PostDate)*2) <= 14) then '1'
WHEN (Clients.ClntGroup = 'Export Market') or Clients.CustCateg = 'UK Transfer' AND (d.DateDue >= CDSPDocs.PostDate) then '1'
ELSE '0'
END as OnTxO
From dbo.Documents AS d INNER JOIN
dbo.Clients ON d.ObjectID = dbo.Clients.ClntID AND Clients.ClientName <> 'Samples - Free / Give-aways' LEFT Outer JOIN
dbo.DocumentsLines AS CORDLines ON d.DocID = CORDLines.DocID AND CORDLines.TrnType = 'L'
LEFT OUTER JOIN
dbo.DocumentsLines AS CDSPLines ON CORDLines.TranID = CDSPLines.SourceID AND CDSPLines.TrnType = 'L' AND (CDSPLines.Status = 'Posted' OR CDSPLines.Status = 'Closed') LEFT OUTER JOIN
dbo.Documents AS CDSPDocs ON CDSPLines.DocID = CDSPDocs.DocID
WHERE (d.DocType IN ('CASW', 'CORD','MORD'))
AND (CORDLines.LneType NOT In ('Fght','MANF','Stor', 'PACK','EXPS'))
AND d.DateOpn >= #StartDate AND d.DateOpn < #EndDate
AND (CORDLines.LneType is not null)
AND (d.DateDue <= Convert(Date, GetDate(), 101))
Group by d.DateOpn
,d.DocumentCode
,Clients.CustCateg
,CDSPDocs.DocumentCode
,d.[Status]
,d.DocType
,d.OpenDate
,d.DateReq
,CDSPDocs.PostDate
,CDSPLines.[Status]
,Clients.ClntGroup
,d.DocumentName
,d.DateDue
,d.DateOpn
ORDER BY d.DateOpn, 'Week#'
END
GO
All help is appreciated.
Thanks
H
Below is an example that wraps the original query in a derived table so that you don't need to repeat the CASE expressions for the SUM. You could similarly wrap the query in a common table expression to achieve the same result.
I suggest you use single-quotes only to enclose string literals and enclose identifiers (column names, aliases, and object names) with either square brackets or double quotes as described in the SQL Server Books Online reference (http://msdn.microsoft.com/en-us/library/ms175874.aspx). Identifiers need be enclosed only when they don't conform to identifier naming rules or are a reserved keyword.
ALTER PROC dbo.DIFOTIS #Mode AS varchar(5)
AS
BEGIN
DECLARE #StartDate date
, #EndDate date;
SET #StartDate = CASE #Mode
WHEN 'MTD'
THEN DATEADD(mm, DATEDIFF(mm, 0, GETDATE()), 0)
WHEN 'YTD'
THEN DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0)
WHEN 'QTD'
THEN DATEADD(qq, DATEDIFF(qq, 0, GETDATE()), 0)
WHEN 'WTD'
THEN DATEADD(wk, DATEDIFF(wk, 0, GETDATE()), 0)
END;
SET #EndDate = CASE #Mode
WHEN 'MTD'
THEN DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0)
WHEN 'YTD'
THEN DATEADD(yy, DATEDIFF(yy, 0, GETDATE()) + 1, 0)
WHEN 'QTD'
THEN DATEADD(qq, DATEDIFF(qq, 0, GETDATE()) + 1, 0)
WHEN 'WTD'
THEN DATEADD(wk, DATEDIFF(wk, 0, GETDATE()) + 1, 0)
END;
SELECT Week#
, CustCateg
, ClntGroup
, CORD_DocumentCode
, DESP_DocumentCode
, Cord_Lines
, CORD_Qty
, DESP_Lines
, DESP_Qty
, Status
, d_status
, OpenDate
, DateDue
, DESP_PostedDate
, DocType
, [Lead times]
, InFxO
, OnTxO
, InFxO + OnTxO AS InFullAndOneTime
FROM (
SELECT DATEPART(ISO_WEEK, d.DateOpn) AS Week#
, Clients.CustCateg
, Clients.ClntGroup
, d.DocumentCode AS CORD_DocumentCode
, CDSPDocs.DocumentCode AS DESP_DocumentCode
, COUNT(CORDLines.Qnty) AS Cord_Lines
, SUM(CORDLines.Qnty) AS CORD_Qty
, COUNT(CDSPLines.Qnty) AS DESP_Lines
, SUM(CDSPLines.Qnty) AS DESP_Qty
, CDSPLines.Status
, d.Status AS d_status
, d.OpenDate
, d.DateDue
, CDSPDocs.PostDate AS DESP_PostedDate
, d.DocType
, DATEDIFF(DAY, d.OpenDate, d.DateDue) AS [Lead times]
--in-full
, CASE WHEN SUM(CORDLines.Qnty) = SUM(CDSPLines.Qnty) THEN 1
ELSE 0
END AS InFxO
--On-Time by order according to Despatch SLAs
, CASE WHEN ( Clients.ClntGroup IN ( 'Local Market',
'Local Market - Pharm',
'Web Sales - Local',
'Web Sales - Export',
'Mail Order',
'Mail Order - Export' ) )
AND ( DATEDIFF(DAY, d.OpenDate, CDSPDocs.PostDate)
- ( DATEDIFF(WEEK, d.OpenDate,
CDSPDocs.PostDate) * 2 ) <= 2 )
THEN 1
WHEN ( Clients.ClntGroup = 'Export Market' )
AND ( DATEDIFF(DAY, d.OpenDate, CDSPDocs.PostDate)
- ( DATEDIFF(WEEK, d.OpenDate,
CDSPDocs.PostDate) * 2 ) <= 14 )
THEN 1
WHEN ( Clients.ClntGroup = 'Export Market' )
OR Clients.CustCateg = 'UK Transfer'
AND ( d.DateDue >= CDSPDocs.PostDate ) THEN '1'
ELSE 0
END AS OnTxO
FROM dbo.Documents AS d
INNER JOIN dbo.Clients ON d.ObjectID = dbo.Clients.ClntID
AND Clients.ClientName <> 'Samples - Free / Give-aways'
LEFT OUTER JOIN dbo.DocumentsLines AS CORDLines ON d.DocID = CORDLines.DocID
AND CORDLines.TrnType = 'L'
LEFT OUTER JOIN dbo.DocumentsLines AS CDSPLines ON CORDLines.TranID = CDSPLines.SourceID
AND CDSPLines.TrnType = 'L'
AND ( CDSPLines.Status = 'Posted'
OR CDSPLines.Status = 'Closed'
)
LEFT OUTER JOIN dbo.Documents AS CDSPDocs ON CDSPLines.DocID = CDSPDocs.DocID
WHERE ( d.DocType IN ( 'CASW', 'CORD', 'MORD' ) )
AND ( CORDLines.LneType NOT IN ( 'Fght', 'MANF', 'Stor',
'PACK', 'EXPS' ) )
AND d.DateOpn >= #StartDate
AND d.DateOpn < #EndDate
AND ( CORDLines.LneType IS NOT NULL )
AND ( d.DateDue <= CONVERT(date, GETDATE(), 101) )
GROUP BY d.DateOpn
, d.DocumentCode
, Clients.CustCateg
, CDSPDocs.DocumentCode
, d.Status
, d.DocType
, d.OpenDate
, d.DateReq
, CDSPDocs.PostDate
, CDSPLines.Status
, Clients.ClntGroup
, d.DocumentName
, d.DateDue
, d.DateOpn
) AS derived_table
ORDER BY d.DateOpn
, Week#;
END;
GO