Need to optimize a SQL Query - sql

Here is the where clause of the SQL. when I'm removing this part, it's taking 3 mins to execute, with this one it's taking more than 15 mins
there are almost 9000 records in DB
WHERE username = 'xyz' AND
(
( acceptedfordeliverytime BETWEEN '2012-9-1' AND '2013-1-29' )
OR
(
YEAR(acceptedfordeliverytime) = YEAR('2013-1-29')
AND
MONTH(acceptedfordeliverytime) = MONTH('2013-1-29')
AND
DAY(acceptedfordeliverytime) = DAY('2013-1-29')
)
OR
(
YEAR(acceptedfordeliverytime) = YEAR('2012-9-1')
AND
MONTH(acceptedfordeliverytime) = MONTH('2012-9-1')
AND
DAY(acceptedfordeliverytime) = DAY('2012-9-1')
)
)

Why don't you just use:
WHERE username = 'xyz' AND
(acceptedfordeliverytime >= '2012-09-01' AND
acceptedfordeliverytime < '2013-01-30'
)
This will also allow an index on (username, acceptedfordeliverytime) to be used when executing the query.

I think this will give you the same results.
and also make an index for column acceptedfordeliverytime to speed up searching.
WHERE username = 'xyz' AND acceptedfordeliverytime BETWEEN '2012-9-1' AND '2013-1-29'

Isn't BETWEEN inclusive? This would mean that you don't need all the extra clauses (that check for the first and last date in a VERY elaborate way). I believe your query would return the same result if you just did:
WHERE username = 'xyz' AND
(
acceptedfordeliverytime BETWEEN '2012-9-1' AND '2013-1-29'
)

Your both OR part is unnecessary.
when you use
acceptedfordeliverytime Between '2012-9-1' AND '2013-1-29'
It used both date included so OR part is not needed. if you have date and time in your database then you can convert it into date like this
CAST(acceptedfordeliverytime as date) Between '2012-9-1' AND '2013-1-29'

Related

How to exclude SQL variable in output

I have a complex SQL query where I have a few cases that use END AS variableName. I then use variableName to do some logic and then create a new variable which I want in the output result. However when I run the query, all the END AS variableNames that I have used are also outputted in the results.
Is there a way that I can exclude these variables as I only want the final variable that uses these variableNames.
Thanks
EDIT, here is a query explaining my problem
SELECT DISTINCT
mt.src_id AS “SRC_ID”,
CASE
WHEN mt.cd = ‘TAN’ THEN
(
(
SELECT SUM(src_amt)
FROM source_table st
WHERE mt.id = st.id
AND st._cd = ‘TAN’
AND st.amt_cd = ‘ABL’)
)
END AS src_amt
FROM MAIN_TABLE mt
WHERE
mf.dt >= 2021-12-12
AND SRC_AMT > 10
I need SRC_AMT to be used as some sort of logic but when I run the query, it prints out in the output as it's own column. I want to ignore this variable
you can wrap the whole thing into a new select-statement:
select SRC_ID from ( <entire previous query here> )

Is there any option to replace NVL in where clause for parameter

I have been using NVL in my WHERE clause and it worked well till now.
But in such case where the column has NULL value and parameter was also NULL, it didnt return any query.
select * from Table
where
f_date BETWEEN NVL(:F_DATE_FROM,F_DATE) AND NVL(:F_DATE_TO,F_DATE)
AND op_code = NVL(:CODE, OP_CODE)
AND T_CBC = NVL(:TO_CBC,T_CBC)
order by fiscal_date desc
I updated the query as below, and it returns me all the records as expected. However it takes way too long to execute the query. The original query took 1.5min and the new query takes 7min. Is there any way to fine tune the below query please?
select * from Table
where
f_date BETWEEN NVL(:F_DATE_FROM,F_DATE) AND NVL(:F_DATE_TO,F_DATE)
AND (OP_CODE = :CODE or :CODE is null)
AND (T_CBC = :TO_CBC or :TO_CBC is null)
order by fiscal_date desc
Sure:
WHERE
(f_date >= :F_DATE_FROM OR :F_DATE_FROM IS NULL) AND
(f_date <= :F_DATE_TO OR :F_DATE_TO IS NULL) AND
...
though I'm not sure how much of a performance improvement it'll realize. If your query is about performance specifically, ask a question that includes a query plan

how do I join two tables sql

I have an issue that I'm hoping you can help me with. I am trying to create charting data for performance of an application that I am working on. The first step for me to perform two select statements with my feature turned off and on.
SELECT onSet.testName,
avg(onSet.elapsed) as avgOn,
0 as avgOff
FROM Results onSet
WHERE onSet.pll = 'On'
GROUP BY onSet.testName
union
SELECT offSet1.testName,
0 as avgOn,
avg(offSet1.elapsed) as avgOff
FROM Results offSet1
WHERE offSet1.pll = 'Off'
GROUP BY offSet1.testName
This gives me data that looks like this:
Add,0,11.4160277777777778
Add,11.413625,0
Delete,0,4.5245277777777778
Delete,4.0039861111111111,0
Evidently union is not the correct feature. Since the data needs to look like:
Add,11.413625,11.4160277777777778
Delete,4.0039861111111111,4.5245277777777778
I've been trying to get inner joins to work but I can't get the syntax to work.
Removing the union and trying to put this statement after the select statements also doesn't work. I evidently have the wrong syntax.
inner join xxx ON onSet.testName=offset1.testName
After getting the data to be like this I want to apply one last select statement that will subtract one column from another and give me the difference. So for me it's just one step at a time.
Thanks in advance.
-KAP
I think you can use a single query with conditional aggregation:
SELECT
testName,
AVG(CASE WHEN pll = 'On' THEN elapsed ELSE 0 END) AS avgOn,
AVG(CASE WHEN pll = 'Off' THEN elapsed ELSE 0 END) AS avgOff
FROM Results
GROUP BY testName
I just saw the filemaker tag and have no idea if this work there, but on MySQL I would try something along
SELECT testName, sum(if(pll = 'On',elapsed,0)) as sumOn,
sum(if(pll = 'On',1,0)) as numOn,
sum(if(pll ='Off',elapsed,0)) as sumOff,
sum(if(pll ='Off',1,0)) as numOff,
sumOn/numOn as avgOn,
sumOff/numOff as avgOff
FROM Results
WHERE pll = 'On' or pll='Off'
GROUP BY testName ;
If it works for you then this should be rather efficient as you do not need to join. If not, thumbs pressed that this triggers another idea.
The difficulty you have with the join you envisioned is that the filtering in the WHERE clause is performed after the join was completed. So, you would still not know what records to use to compute the averages. If the above is not implementable with FileMaker then check if nested queries work. You would then
SELECT testName, on.avg as avgOn, off.avg as avgOff
FROM ( SELECT ... FROM Results ...) as on, () as off
JOIN on.testName=off.testName
If that is also not possible then I would look for temporary tables.
OK guys... thanks for the help again. Here is the final answer. The statement below is FileMaker custom function that takes 4 arguments (platform, runID, model and user count. You can see the sql statement is specified. FileMaker executeSQL() function does not support nested select statements, does not support IF statements embedded in select statements (calc functions do of course) and finally does not support the SQL keyword VALUES. FileMaker does support the SQL keyword CASE which is a little more powerful but is a bit wordy. The select statement is in a variable named sql and result is placed in a variable named result. The ExecuteSQL() function works like a printf statement for param text so you can see the swaps do occur.
Let(
[
sql =
"SELECT testName, (sum( CASE WHEN PLL='On' THEN elapsed ELSE 0 END)) as sumOn,
sum( CASE WHEN PLL='On' THEN 1 ELSE 0 END) as countOn,
sum( CASE WHEN PLL='Off' THEN elapsed ELSE 0 END) as sumOff,
sum( CASE WHEN PLL='Off' THEN 1 ELSE 0 END) as countOff
FROM Results
WHERE Platform = ?
and RunID = ?
and Model = ?
and UserCnt = ?
GROUP BY testName";
result = ExecuteSQL ( sql ; "" ; ""
; platform
; runID
; model
; userCnt )
];
getAverages ( Result ; "" ; 2 )
)
For those interested the custom function looks like this:
getAverages( result, newList, pos )
Let (
[
curValues = Substitute( GetValue( data; pos ); ","; ¶ );
sumOn = GetValue( curValues; 2 ) ;
countOn = GetValue( curValues; 3 );
sumOff = GetValue( curValues; 4 );
countOff = GetValue( curValues; 5 );
avgOn = sumOn / countOn;
avgOff = sumOff / countOff
newItem = ((avgOff - avgOn) / avgOff ) * 100
];
newList & If ( pos > ValueCount( data); newList;
getAverages( data; If ( not IsEmpty( newList); ¶ ) & newItem; pos + 1 ))
)

LAST REG From a Query SQL

I'm trying to get the last record from this query but i don't know how to do it. I used ROW_NUMBER but my program (Protheus ADVPL) don't have resources to get the last line from a query
SELECT ROW_NUMBER() OVER (ORDER BY B1_MASTER, B1_COD) AS ID,
B1_COD,
B1_DESC,
B1_CATEG,
B1_MASTER,
A2_COMPRAD,
ISNULL((SELECT Sum(C6_QTDVEN * C6_PRCVEN)
FROM SC6010 SC6,
SF4010 SF4,
SC5010 SC5
WHERE C6_FILIAL = '01'
AND C6_PRODUTO = B1_COD
AND SC6.D_E_L_E_T_ <> '*'
AND C5_FILIAL = C6_FILIAL
AND C5_NUM = C6_NUM
AND C5_EMISSAO BETWEEN '20160401' AND '20160404'
AND C5_TIPO = 'N'
AND C5_MODAL = '2'
AND SC5.D_E_L_E_T_ <> '*'
(query have 106 lines so i ll not put everything)
I need the total records in a column, like this:
Tabela
What can i do?
Tks
You can use MAX(field) too.
But, you're using ADVPL, so you could use dbSeek instead to find the last RECNO.
So, using "work area" you can find the last record with this:
TRB->(RECCOUNT())
I changed ROW_NUMBER to ##ROWCOUNT and it works! Tks all

sql select with one value of two where

This is the only place that I get all answer ;)
I want to select :
SELECT
RTRIM(LTRIM(il.Num_bloc)) AS Bloc,
RTRIM(LTRIM(il.num_colis)) AS Colis,
cd.transporteur AS Coursier,
cd.origine AS Origine,
cd.destination AS Destinataire,
cd.adresse AS [Adresse Destinataire],
cd.poids AS Poids,
il.Signataire, il.num_cin AS CIN, il.date_livraison AS [Date Livraison]
FROM
dbo.cd
INNER JOIN
dbo.il ON cd.bloc = il.Num_bloc AND dbo.cd.colis = dbo.il.num_colis
WHERE
(il.Num_bloc = RTRIM(LTRIM(#ParamBloc)))
AND (il.num_colis = RTRIM(LTRIM(#ParamColis)))
In the way of getting result if the user put ether #ParamBloc or #ParamColis
Try using IsNull() function.
A simple query would go like this
Select * from yourTable
Where
Num_bloc = ISNULL(#ParamBloc, Num_block) AND
num_colis = ISNULL(#ParamColis, num_colis)
The second parameter would make the expression to true if the #parameter Bloc or Colis is null. This query would be useful for all 4 possible combination of these two parameter.