I have written a query, but appears to run quite slowly in our live environment.
The query contains nested select statements which I believe to slow down execution.
Does anyone have any tips of how I could re-write the query to improve the execution speed.
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = '20140101'
SET #EndDate = '20140101'
SELECT a.applicationid,
a.ourreference,
(SELECT MAX(e.CreateDateTime) FROM tblEmail AS e WHERE( e.ApplicationID = a.ApplicationID) AND (ISNULL(e.StandardEmailID,0) <> 3)) AS 'LastEmail',
(SELECT MAX(l.CreateDateTime) FROM tblLetter AS l WHERE l.ApplicationID = a.ApplicationID AND l.ExternalDocumentTypeID IS NULL) AS 'LastInternalLetter',
(SELECT MAX(l.CreateDateTime) FROM tblLetter AS l WHERE l.ApplicationID = a.ApplicationID AND l.ExternalDocumentTypeID IS NOT NULL) AS 'LastExternalLetter'
INTO #Temp
FROM tblapplication AS a
WHERE (a.LogDate BETWEEN #StartDate AND #EndDate + '23:59:59')
AND (a.BusinessSourceID NOT IN (11, 16))
AND (a.ApplicationStatusID = 100)
SELECT *
FROM #Temp AS tem
WHERE ((LastEmail < LastExternalLetter) AND (LastInternalLetter < LastExternalLetter))
Cheers everyone
edit- Sorry I should say what the query is for. I am trying to see if our customers have sent us a letter and we haven't responded to them with a letter/email
select *
from
(
Select a.applicationId, a.ourreference,
max(e.CreateDateTime) LastEmail,
max(li.CreateDateTime) LastInternalLetter,
max(le.CreateDateTime) LastExternalLetter
from tblApplication a
left outer join tblEmail e on e.ApplicationID = a.ApplicationID
left outer join tblLetter li on li.ApplicationId = a.ApplicationId
left outer join tblLetter le on le.ApplicationId = a.ApplicationId
WHERE (a.LogDate BETWEEN #StartDate AND #EndDate + '23:59:59')
AND (a.BusinessSourceID NOT IN (11, 16))
AND (a.ApplicationStatusID = 100)
and (e.StandardEmailID <> 3 or e.StandardEmailId is null)
group by a.ApplicationId, a.OurReference
)x
WHERE ((LastEmail < LastExternalLetter) AND (LastInternalLetter < LastExternalLetter))
This gets rid of the temporary table. Remember, with SQL wherever you have a Table you can substitute a query (in Selects anyway). This should make it a bit more efficient, but you want to look at the Query Plans and see what's holding it up.
Cheers -
Related
I'm trying to create a query to fetch dynamics AX salestable records with their history log records in a left join.
If I filter on the salesid I naturally get the results in a split second, but if I leave out the salesid it takes forever even though SalesID SN16129492 is the only 'valid' record for 2017/03/08?:
Declare #Bedrijf NVARCHAR(3) = 'dat';
Declare #leverdatum_van DATE = convert(datetime, '2017/03/08');
Declare #leverdatum_tot DATE = convert(datetime, '2017/03/08');
Declare #bedrag decimal = 1;
SELECT SUM(SALESLINE.LINEAMOUNT) AS waarde, SALESTABLE.CUSTACCOUNT, SALESTABLE.SALESID as ordernummer, CUSTTABLE.NAME as klantnaam,
MAX(SalesTable.createdBy) as ingevoerd_door, log.dader, log.veldnummer, log.huidigestatus, log.vorigestatus
FROM SALESLINE INNER JOIN
SALESTABLE ON SALESLINE.SALESID = SALESTABLE.SALESID AND SALESLINE.DATAAREAID = SALESTABLE.DATAAREAID
INNER JOIN CUSTTABLE ON
SALESTABLE.DATAAREAID=CUSTTABLE.DATAAREAID AND SALESTABLE.CUSTACCOUNT=CUSTTABLE.ACCOUNTNUM
LEFT JOIN
(select dbo.CONPEEK(CAST(dbo.CONPEEK(data, 2) AS varbinary(8000)), 2) AS DADER,
dbo.CONPEEK(CAST(dbo.CONPEEK(data, 5) AS varbinary(8000)), 1) AS VELDNUMMER,
dbo.CONPEEK(CAST(dbo.CONPEEK(data, 5) AS varbinary(8000)), 2) AS HUIDIGESTATUS,
dbo.CONPEEK(CAST(dbo.CONPEEK(data, 5) AS varbinary(8000)), 3) AS VORIGESTATUS, LOGRECID
from SYSDATABASELOG
where TABLE_=366 AND DATAAREAID=#bedrijf
) log
ON SALESTABLE.DATAAREAID=#bedrijf AND SALESTABLE.RECID=log.LOGRECID
WHERE (SALESLINE.DATAAREAID = #bedrijf) AND SALESTABLE.SALESTYPE=4 --retourorder
AND (SALESTABLE.SHIPPINGDATEREQUESTED between #leverdatum_van and #leverdatum_tot)
--AND (Salestable.SALESID = 'SN16129492')
AND (SALESTABLE.SalesOrderStatus in (0,1,2,3,4,5))
GROUP BY SALESTABLE.CUSTACCOUNT, SALESTABLE.SALESID, CUSTTABLE.NAME, log.dader, log.veldnummer, log.huidigestatus, log.vorigestatus
HAVING (SUM(ABS(SALESLINE.LINEAMOUNT))> #bedrag)
Is there a way to improve performance / redesign this query?
You must explicitly include dataareaid AND partition in conditions for all tables (you can either add it as a filter, or in join conditions), even if you just have a single partition.
By default, AX2012 implicitly adds the dataareaid and partition fields to all indexes created in the AOT as the first two fields.
As we found, SQL server is notoriously bad with handling these kinds of indexes, apart from the fact that it can't just "skip" the first level if you don't provide it explicitly (partition), it is also really bad at estimating index statistics (SQL server does a histogram for the first field in the index, and assumes the rest of the fields in the index have a normal distribution).
This is not an answer, but I couldn't write code so long in a comment.
The result could be different, but it's just to help us understand if a part of your query degrade performance (GROUP BY). I moved part of group fields outside.
Can you try this and see if it is "going forever" (using your words)?
SELECT A.*
,log.dader
,log.veldnummer
,log.huidigestatus
,log.vorigestatus
FROM (
SELECT SUM(SALESLINE.LINEAMOUNT) AS waarde
,SALESTABLE.CUSTACCOUNT
,SALESTABLE.SALESID AS ordernummer
,CUSTTABLE.NAME AS klantnaam
,MAX(SalesTable.createdBy) AS ingevoerd_door
,SALESTABLE.RECID /* ADDED THIS */
FROM SALESLINE
INNER JOIN SALESTABLE ON SALESLINE.SALESID = SALESTABLE.SALESID AND SALESLINE.DATAAREAID = SALESTABLE.DATAAREAID
INNER JOIN CUSTTABLE ON SALESTABLE.DATAAREAID = CUSTTABLE.DATAAREAID AND SALESTABLE.CUSTACCOUNT = CUSTTABLE.ACCOUNTNUM
WHERE SALESLINE.DATAAREAID = #bedrijf
AND SALESTABLE.SALESTYPE = 4 --retourorder
AND SALESTABLE.SHIPPINGDATEREQUESTED BETWEEN #leverdatum_van AND #leverdatum_tot
--AND (Salestable.SALESID = 'SN16129492')
AND SALESTABLE.SalesOrderStatus IN (0, 1, 2, 3, 4, 5)
GROUP BY SALESTABLE.CUSTACCOUNT
,SALESTABLE.SALESID
,CUSTTABLE.NAME
,SALESTABLE.RECID /* ADDED THIS */
HAVING SUM(ABS(SALESLINE.LINEAMOUNT)) > #bedrag
) A
LEFT JOIN (SELECT dbo.CONPEEK(CAST(dbo.CONPEEK(data, 2) AS VARBINARY(8000)), 2) AS DADER
,dbo.CONPEEK(CAST(dbo.CONPEEK(data, 5) AS VARBINARY(8000)), 1) AS VELDNUMMER
,dbo.CONPEEK(CAST(dbo.CONPEEK(data, 5) AS VARBINARY(8000)), 2) AS HUIDIGESTATUS
,dbo.CONPEEK(CAST(dbo.CONPEEK(data, 5) AS VARBINARY(8000)), 3) AS VORIGESTATUS
,LOGRECID
FROM SYSDATABASELOG
WHERE TABLE_ = 366
AND DATAAREAID = #bedrijf) log ON SALESTABLE.RECID = log.LOGRECID
By adding filters for createddatetime for bot left and right table I've decreased processing time from 'forever' to < 30 seconds for a period of one month.
Optimized Query:
Declare #Bedrijf NVARCHAR(3) = 'dat';
Declare #leverdatum_van DATETIME = convert(datetime, '2017/03/01');
Declare #leverdatum_tot DATETIME = convert(datetime, '2017/04/01');
Declare #bedrag decimal = 1;
SELECT SUM(SALESLINE.LINEAMOUNT) AS waarde, SALESTABLE.CUSTACCOUNT, SALESTABLE.SALESID as ordernummer, CUSTTABLE.NAME as klantnaam,
MAX(SalesTable.createdBy) as ingevoerd_door, log.dader, log.veldnummer, log.huidigestatus, log.vorigestatus
FROM SALESLINE
INNER JOIN SALESTABLE
ON SALESLINE.SALESID = SALESTABLE.SALESID AND SALESLINE.DATAAREAID = SALESTABLE.DATAAREAID
INNER JOIN CUSTTABLE
ON SALESTABLE.DATAAREAID=CUSTTABLE.DATAAREAID AND SALESTABLE.CUSTACCOUNT=CUSTTABLE.ACCOUNTNUM
LEFT JOIN (
select dbo.CONPEEK(CAST(dbo.CONPEEK(data, 2) AS varbinary(8000)), 2) AS DADER,
dbo.CONPEEK(CAST(dbo.CONPEEK(data, 5) AS varbinary(8000)), 1) AS VELDNUMMER,
dbo.CONPEEK(CAST(dbo.CONPEEK(data, 5) AS varbinary(8000)), 2) AS HUIDIGESTATUS,
dbo.CONPEEK(CAST(dbo.CONPEEK(data, 5) AS varbinary(8000)), 3) AS VORIGESTATUS, LOGRECID
from SYSDATABASELOG
where TABLE_=366 AND DATAAREAID=#bedrijf
and createddatetime between #leverdatum_van and #leverdatum_tot
) log
ON SALESTABLE.DATAAREAID=#bedrijf AND SALESTABLE.RECID=log.LOGRECID
WHERE (SALESLINE.DATAAREAID = #bedrijf) AND SALESTABLE.SALESTYPE=4 --retourorder
AND (SALESTABLE.createddatetime between #leverdatum_van and #leverdatum_tot)
--AND (Salestable.SALESID = 'SN16129492')
AND (SALESTABLE.SalesOrderStatus in (0,1,2,3,4,5))
GROUP BY SALESTABLE.CUSTACCOUNT, SALESTABLE.SALESID, CUSTTABLE.NAME, log.dader, log.veldnummer, log.huidigestatus, log.vorigestatus
HAVING (SUM(ABS(SALESLINE.LINEAMOUNT))> #bedrag)
More clustered index seeks in the new execution plan:
Thnx for helping me out ;)
I have a problem.
I'm trying to get a BIT value to check whether a person has entered the building last night between 10pm to midnight. When I run the subquery code by itself, it gives me the results I need. As I'm working with SSRS2008 I need for all the results to be in the same stored procedure.
So the problem is, it gives me the bit values somewhat right, for the ones that are obviously false, it gives false, for the ones that are obviously true, it gives true. But for the ones in the middle (the day shift, who leave at 23) it gives the results somewhat random..
Does anyone have a clue?
SELECT DISTINCT TOP 200
Events.LoggedTime,
PTUsers.Name,
PTDoors.PTDoorsID,
PTUsers.AccessLevel,
CAST(CASE
WHEN EXISTS (SELECT Events.LoggedTime
FROM Events
INNER JOIN PTUsers AS PTUsers_1 ON Events.GlobalIndex1 = PTUsers.GlobalRecord
INNER JOIN PTDoors AS PTDoors_1 ON Events.RecordIndex2 + 1 = PTDoors.Address
WHERE (DATEPART(day, Events.LoggedTime) = DATEPART(day, GETDATE() - 1))
AND (DATEPART(hour, Events.LoggedTime) IN (22, 23))
AND (PTDoors_1.PTDoorsID = 14)) THEN 1 ELSE 0 END AS BIT) AS Night
FROM
Events
INNER JOIN
PTUsers ON Events.GlobalIndex1 = PTUsers.GlobalRecord
INNER JOIN
PTDoors ON Events.RecordIndex2 + 1 = PTDoors.Address
WHERE
(PTUsers.Panel = 0)
AND (PTDoors.Panel = 0)
AND (PTDoors.PTDoorsID = 14)
AND (DATEPART(day, Events.LoggedTime) = DATEPART(day, GETDATE()) - 1)
AND (PTUsers.AccessLevel IN (3))
ORDER BY
Events.LoggedTime DESC
#lrd i did the corrections you suggested,
thanks for pointing out the table aliases :)
i removed the cast, so now i get the BIT column. but now the problem is that i get all "1"'s as results.
What baffles me is the that subquery works as it should as a query on it's own. it goes back a day, and displays the entries on that door in the given timeframe.
now i'm trying to compare that information for the same person, meaning - i see a person in the list, arriving yesterday at 6am, check if that person also arrived the day before that between 22 & midnight and return a bit value to display that.
SELECT DISTINCT TOP 200 Events.LoggedTime, PTUsers.Name, PTDoors.PTDoorsID, PTUsers.AccessLevel, CASE WHEN EXISTS
(SELECT Events.LoggedTime
FROM Events INNER JOIN
PTUsers AS PTUsers_1 ON Events.GlobalIndex1 = PTUsers_1.GlobalRecord INNER JOIN
PTDoors AS PTDoors_1 ON Events.RecordIndex2 + 1 = PTDoors_1.Address
WHERE (DATEPART(day, Events.LoggedTime) = DATEPART(day, GETDATE() - 1)) AND (DATEPART(hour, Events.LoggedTime) IN (22, 23)) AND
(PTDoors_1.PTDoorsID = 14)) THEN 1 ELSE 0 END AS BIT
FROM Events INNER JOIN
PTUsers ON Events.GlobalIndex1 = PTUsers.GlobalRecord INNER JOIN
PTDoors ON Events.RecordIndex2 + 1 = PTDoors.Address
WHERE (PTUsers.Panel = 0) AND (PTDoors.Panel = 0) AND (PTDoors.PTDoorsID = 14) AND (DATEPART(day, Events.LoggedTime) = DATEPART(day, GETDATE())
- 1) AND (PTUsers.AccessLevel IN (3))
ORDER BY Events.LoggedTime DESC
I don't think you need a CAST because you are explicitly defining Night as a BIT By setting the result to EXISTS(), which is a bit. I removed the query that was incorrect.
I see your problem. You are not using the correct table alias for your join constraint in your subquery.
It should be:
INNER JOIN PTUsers AS PTUsers_1 ON Events.GlobalIndex1 = PTUsers_1.GlobalRecord
INNER JOIN PTDoors AS PTDoors_1 ON Events.RecordIndex2 + 1 = PTDoors_1.Address
Also,check and make sure you are using the correct values in your join. I would change the following for a test.
FROM Events Events_2
INNER JOIN PTUsers AS PTUsers_1 ON Events_2.GlobalIndex1 = PTUsers_1.GlobalRecord
INNER JOIN PTDoors AS PTDoors_1 ON Events_2.RecordIndex2 + 1 = PTDoors_1.Address
I have the following 2 Join Statements:
--Get Total Hrs
DECLARE #BeginDate datetime, #EndDate datetime
set #BeginDate = '01-01-2013'
set #EndDate = '12-31-2013'
BEGIN
SELECT F.Type, E.Product, SUM(F.Hours * E.Amount) AS 'Total Hours'
FROM Hours H
INNER JOIN Equipment E
ON F.SN = E.SN
WHERE (F.Date BETWEEN #BeginDate AND #EndDate)
GROUP BY F.Type, E.Product
ORDER BY Product ASC
END
--Get Number of Unscheduled Removals
DECLARE #BeginDate1 datetime, #EndDate1 datetime
set #BeginDate1 = '01-01-2013'
set #EndDate1 = '12-31-2013'
BEGIN
SELECT LEFT(dbo.fn_GetPartName(R.PartID),CHARINDEX('-',dbo.fn_GetPartName(R.PartID), 1) - 1) AS 'Part No',
Count(s.status) AS NumberUnscheduledRemovals
FROM Repair R
INNER JOIN Conversion C
ON R.Performed = C.Performed
AND R.Confirmed = C.Confirmed
INNER JOIN Status S
ON C.StatusID = S.StatusID
WHERE (R.Received BETWEEN #BeginDate1 AND #EndDate1)
AND (S.Status = 'UNSCHEDULED')
GROUP BY LEFT(dbo.fn_GetPartName(R.PartID),CHARINDEX('-',dbo.fn_GetPartName(R.PartID), 1) - 1)
ORDER BY LEFT(dbo.fn_GetPartName(R.PartID),CHARINDEX('-',dbo.fn_GetPartName(R.PartID), 1) - 1) ASC
END
Both queries have results including part numbers (these have the same values). I want to INNER JOIN the results from both queries on the resulting part numbers. have been trying for a while but cant seem to get the syntax right to do it.
Use a temp table using CREATE TABLE #TempPartNum1 & #TempPartNum2.
Grab all the relevant data from the first two queries and put them in the temp tables, then join the temp tables.
You could also use a CTE ("Common Table Expression"):
;WITH QueryOne AS (
... put your first query here
), QueryTwo AS (
... put your second query here
) SELECT blah blah blah
FROM QueryOne INNER JOIN QueryTwo ON foo = bar
CTEs are very handy for things like this.
I'm doing a weight reporting and I have a problem. I use this query to know the enters of weight in our warehouse, but when there are no transactions in a date this date doesn't appears in the results.
SELECT erp.MKPF.BUDAT AS Data,
Sum( erp.MSEG.MENGE * erp.MARM.BRGEW ) as pes
From erp.MKPF
INNER Join erp.MSEG on erp.MKPF.MANDT = erp.MSEG.MANDT and erp.MKPF.MBLNR = erp.MSEG.MBLNR
INNER Join erp.MARM on erp.MSEG.MANDT = erp.MARM.MANDT and erp.MSEG.MATNR = erp.MARM.MATNR And erp.MSEG.MEINS = erp.MARM.MEINH
INNER JOIN erp.MARA on erp.MSEG.MANDT = erp.MARA.MANDT and erp.MSEG.MATNR = erp.MARA.MATNR
WHERE erp.MKPF.MANDT = '100'
and erp.MKPF.BUDAT >= '20120720'
and erp.MKPF.BUDAT <= CONVERT(VARCHAR(8), GETDATE(), 112) -1
and erp.MSEG.LGORT in ('1001','1069')
and erp.MSEG.BWART In ('101','102','311','312')
and erp.MSEG.WERKS = '1001'
and erp.MARA.MTART in ('Z001','Z010','Z002','Z02E')
GROUP BY erp.MKPF.BUDAT*
Now the results are like this:
Data PES
20120720 9999999.9999
20120721 9999999.8888
20120723 9999999.7777
And i need this
Data PES
20120720 9999999.9999
20120721 9999999.8888
20120722 0
20120723 999999.7777
Can somebody help me?
Use a table or a view to generate the date range of interest and let this drive the query. Then you outer join your results to this view. This can be done dynamically in the query. For example, in Oracle, you can use "connect by" to generate a series:
create table my_summary(the_day date, pes number);
insert into my_summary values(to_date('20120720', 'yyyymmdd'), 9999999.9999);
insert into my_summary values(to_date('20120721', 'yyyymmdd'), 9999999.8888);
insert into my_summary values(to_date('20120723', 'yyyymmdd'), 9999999.7777);
SELECT d.the_day, NVL(s.pes, 0) AS pes
FROM ( SELECT to_date('20120720', 'yyyymmdd') + level -1 AS the_day
FROM dual CONNECT BY level <= 4) d
LEFT OUTER JOIN my_summary s ON (d.the_day = s.the_day)
ORDER BY 1
THE_DAY PES
--------- ---
20-JUL-12 9999999.9999
21-JUL-12 9999999.8888
22-JUL-12 0
23-JUL-12 9999999.7777
Other rdbms have other methods to generate a series. This will require you to know the start date you want, and the number of records (in the example above 20120720 and 4).
Thanks to all, finally I did this and it works
SELECT
c.BUDAT AS DATA,
CASE When SAP.pes Is Null then '0'
ELSE SAP.pes
END
From
erp.YSD_CALENDAR as c LEFT JOIN
(SELECT
erp.MKPF.BUDAT,
Sum(
erp.MSEG.MENGE
* erp.MARM.BRGEW ) as pes
FROM
erp.MKPF
INNER Join erp.MSEG on erp.MKPF.MANDT = erp.MSEG.MANDT and erp.MKPF.MBLNR = erp.MSEG.MBLNR
INNER Join erp.MARM on erp.MSEG.MANDT = erp.MARM.MANDT and erp.MSEG.MATNR = erp.MARM.MATNR And erp.MSEG.MEINS = erp.MARM.MEINH
INNER JOIN erp.MARA on erp.MSEG.MANDT = erp.MARA.MANDT and erp.MSEG.MATNR = erp.MARA.MATNR
WHERE
erp.MKPF.MANDT = '100'
and erp.MKPF.BUDAT >= '20120720'
and erp.MSEG.LGORT in ('1001','1069')
and erp.MSEG.BWART In ('101','102','311','312')
and erp.MSEG.WERKS = '1001'
and erp.MARA.MTART in ('Z001','Z010','Z002','Z02E')
and erp.MSEG.SHKZG = 'S'
GROUP BY erp.MKPF.BUDAT
) SAP ON SAP.BUDAT = c.BUDAT
WHERE
c.BUDAT >= '20120720'
and c.BUDAT <= CONVERT(VARCHAR(8), GETDATE(), 112)
GROUP BY c.BUDAT, SAP.pes
ORDER BY c.BUDAT
I need create a View for this Query, allowing change m.arq_data and m2.arq_data values when a select uses this View, like:
select * FROM the_view WHERE m.arq_data = X AND m2.arq_data = Y
Here is my current query:
SELECT distinct(p.num_processo),p.num_proc_jud,a.assunto,su.subassunto,ma.Materia,u.Unidade ,M.COD_UNIDADE as cod_serv ,u.Unidade as servidor ,' ' as serv_ativo,
' ' as data_vinc ,' ' as V_ativo, M.motivo,M.data_movimentacao as data_mov_distr ,
(select max(m2.arq_data) from movimentacao m2 where m2.arq_data
BETWEEN '2011-08-01 00:00:00'AND '2011-08-31 23:00:00' and m2.num_processo =
p.num_processo) as Data_Arq_Desarq , status = 'A'
--pra view
, M.arq_data
FROM processo p
INNER JOIN assunto a ON a.cod_assunto = p.cod_assunto
INNER JOIN subassunto su ON su.cod_subassunto = p.cod_subassunto
LEFT JOIN materia ma ON ma.cod_materia = p.cod_materia
inner JOIN movimentacao M on M.num_processo = p.num_processo
INNER JOIN Unidade u ON u.cod_unidade = M.COD_UNIDADE
where
not exists(select * from anexos a where a.num_proc_anexo = p.num_processo and a.ativo = 1)
and not exists(select * from movimentacao m1 where m1.num_movimentacao= M.num_movimentacao and m1.motivo = 10 and m1.arquivado = 0)
and ( not exists (select * from distrib_vincjud d2 where d2.num_processo = p.num_processo)
or p.num_processo in (select d3.num_processo from distrib_vincjud d3
where d3.num_processo = p.num_processo
and d3.cod_servidor not in(select cod_servidor from servidor)
and d3.id_vinc in (select max(d4.id_vinc) from distrib_vincjud d4
where d4.num_processo = d3.num_processo and d4.data_vinc <= M.arq_data )))
and M.COD_UNIDADE in (select M.COD_UNIDADE from movimentacao m2 where
(m2.cod_ORIGEM_MOV = '26000181' or m2.cod_ORIGEM_MOV = '2600000X')and m2.num_processo = p.num_processo)
and p.tipo = 'J'
and M.arq_data >= '2011-08-01 00:00:00'AND M.arq_data <='2011-08-31 23:00:00'
View cannot take parameters. Implement it as table-valued udf instead (or stored procedure).
If you are saying you want to define your view to work with changing dates for conditions like m2.arq_data BETWEEN '2011-08-01 00:00:00'AND '2011-08-31 23:00:00' then it depends what your requirements are.
For instance if this date range will always be between today and 31 days from now then you could change this line to be something like this:
m2.arq_data BETWEEN GetDate() AND DATEADD (dd, 31, GetDate())
If the date range is not something fairly simple that can be defined generically using SQL then you might want to consider using a stored proc or a udf and passing it the date params.