How optimize the performance of SerialNumbers by SalesInvoicesExploded? - exact-online

I have the following query:
select sie.invoicedate sie_invoicedate
, sie.Silitem sle_item
, sie.Silitemcode sle_itemcode
, sie.Silitemdescription sle_itemdescription
, sie.Silnetprice sle_netprice
, sie.Silquantity sle_quantity
, sie.Silunitprice sle_unitprice
, ctr.ctr_code ctr_code
, ctr.ctr_name ctr_name
, ctr.parent_code parent_code
, ctr.parent_name parent_name
, gdlsn.ssrserialnumber serialnumber
from SalesInvoicesExploded sie
join customers#inmemorystorage ctr
on ctr.ctr_id = sie.invoiceto
join GoodsDeliveryLineSerialNumbers gdlsn
on gdlsn.salesorderlineid = sie.silid
where sie.invoicedate >= '2016-01-01'
and sie.invoicedate < '2016-01-03'
order
by sie.invoicedate
How can I get the serial numbers only from the date range? In the debugger I see a lot of requests to Exact Online.

For now, there isn't a very good filter possibility to get the result you want.
The problem is that there is no way to perform the gdlsn.salesorderlineid = sie.silid filter on the data set unless the data sets have been fetched from the other side.
Only specific filters are executed server-side (like your invoicedate >= '2016-01-01'). This is quite a hard nut to crack from the program side.
It would work if you can specify a filter that can be determined on beforehand, like that the date in GoodsDeliveryLineSerialNumbers.Created always comes after the invoicedate. It would mean a significant performance improvement if you can narrow down the set based on that date.
I suggest to use something like this, if possible:
select sie.invoicedate sie_invoicedate
, sie.Silitem sle_item
, sie.Silitemcode sle_itemcode
, sie.Silitemdescription sle_itemdescription
, sie.Silnetprice sle_netprice
, sie.Silquantity sle_quantity
, sie.Silunitprice sle_unitprice
, ctr.ctr_code ctr_code
, ctr.ctr_name ctr_name
, ctr.parent_code parent_code
, ctr.parent_name parent_name
, gdlsn.ssrserialnumber serialnumber
from SalesInvoicesExploded sie
join customers#inmemorystorage ctr
on ctr.ctr_id = sie.invoiceto
join GoodsDeliveryLineSerialNumbers gdlsn
on gdlsn.salesorderlineid = sie.silid
where sie.invoicedate >= '2016-01-01'
and sie.invoicedate < '2016-01-03'
-- add the following line, use a date that for sure will yield the rows:
and gdlsn.created >= '2015-12-01'
--
order
by sie.invoicedate

Related

MySQL query return different results every time

I have the query
SELECT g.f_id as f_code
, ss.f_name as f_storage
, g.f_name as f_goods
, g.f_scancode
, s.f_price
, SUM(s.f_qty*s.f_type) as f_qty
, SUM(s.f_qty*s.f_type)*g.f_saleprice as f_totalsale
FROM a_store s
JOIN c_goods g
ON g.f_id = s.f_goods
JOIN c_storages ss
ON ss.f_id = s.f_store
JOIN a_header h
ON h.f_id = s.f_document
WHERE h.f_date <= '2020-06-22'
AND h.f_state = 1
GROUP
BY g.f_id
, ss.f_name
, g.f_name
, g.f_scancode
, s.f_price
HAVING SUM(s.f_qty*s.f_type) <> 0
ORDER
BY SUM(s.f_qty*s.f_type) asc
Every time this query returns different result and different rows count without the changes in the database. I cant understand, why.
I was change the version of mysql from 5.7 to 8.0 and problem was gone. Why it worked wrong on version 5.7 remains a mystery.

Convert time "28:45" to "4:45" MySQL

I'm looking for a way to order my results based on the actual time. In my table yo can see values like:
1,23:45
2,9:45
3,27:43
When I do a query I would like to know how to order them based on their actual 24 hour time.
Ex:
3,3:43
2,9:45
1,23:45
Notice how it changes 27:43 to 3:43, and creates the order.
Where I am using it, in this query:
SELECT *,COALESCE(ADDTIME(s.`departure_time`,SEC_TO_TIME(rt.delay)),s.`departure_time`) as `rt_time` FROM `stop_times` s INNER JOIN `trips` t ON s.`trip_id` = t.`trip_id` INNER JOIN `stops` st ON st.`stop_id` = s.`stop_id` INNER JOIN `routes` r ON r.`route_id` = t.`route_id` LEFT JOIN `rt_trips` rt ON t.`trip_id` = rt.`trip_id` where (s.`stop_id` = 'CB900') and ( ( s.`departure_time` >= '00:50' and s.`departure_time` <= '05:50') OR ( s.`departure_time` >= '24:50' and s.`departure_time` <= '29:50') ) and (s.`pickup_type` = '0') and (t.`service_id` IN ('removed to make it easier')) HAVING (`rt_time` BETWEEN '01:50' and '05:50' ) ) OR ( `rt_time` BETWEEN '25:50' and '29:50' ) ORDER BY `order` ASC
Explanation:
Information is a transit schedule, that may go forward onto the next day which may be a saturday. So, times may become 25:50, where that means 1:50 the next day.
Thanks
Cyrus
Hmmm, if you just want to get a value between 0 and 24 hours, then I would do:
select concat(mod(substring_index(time_column, ':', 1) + 0, 24), ':',
substring_index(time_column, ':', -1)
)
Try this function on the time_column
concat(mod(substr(time_column,1,INSTR(time_column, ':')-1),24)
,substr(time_column,INSTR(time_column, ':'),3)
)
You might need to cast date to string to integer, do the maths, and again cast it to time. But the fiddle version seems to work properly on varchar to integer conversion. Check this
http://sqlfiddle.com/#!9/ff60f9/1

Error Code: 1054 Unknown column 'tzHour' in 'where clause'

trying to get the following to work, trying to make adjustment for timezone. If I comment out the line AND plan.resetHour=tzHour it shows the column tzHour correctly but can't seem to use the value in the where clause.
SELECT
`issuer`.`tz`
,`account`.`id`
, `plan`.`endDate`
, `plan`.`resetDay`
, `plan`.`resetHour`
, `plan`.`type`
, HOUR(NOW())
, CASE issuer.`tz`
WHEN 'US/Eastern' THEN HOUR(NOW())+1
WHEN 'US/Central' THEN HOUR(NOW())
ELSE HOUR(NOW())
END AS tzHour
FROM
`dvh`.`account`
INNER JOIN `dvh`.`plan`
ON (`account`.`plan` = `plan`.`id`)
INNER JOIN `dvh`.`issuer`
ON (`plan`.`issuer` = `issuer`.`id`)
WHERE plan.type='UNIT'
AND plan.startDate < NOW()
AND plan.endDate >NOW()
AND plan.resetDay=DAYOFWEEK(NOW())
AND plan.resetHour=tzHour
AND account.`active`=1;
Using a column alias in a WHERE clause is illegal. From MySQL docs:
Standard SQL disallows references to column aliases in a WHERE clause. This restriction is imposed because when the WHERE clause is evaluated, the column value may not yet have been determined.
http://dev.mysql.com/doc/refman/5.6/en/problems-with-alias.html
One way to go about this is to move the case into a sub-select.
SELECT
`issuer`.`tz`
,`account`.`id`
, `plan`.`endDate`
, `plan`.`resetDay`
, `plan`.`resetHour`
, `plan`.`type`
, HOUR(NOW())
, tempHour.tzHour
FROM
(
SELECT
CASE `tz`
WHEN 'US/Eastern' THEN HOUR(NOW())+1
WHEN 'US/Central' THEN HOUR(NOW())
ELSE HOUR(NOW())
END AS tzHour
FROM issuer
) AS tempHour,
`dvh`.`account`
INNER JOIN `dvh`.`plan`
ON (`account`.`plan` = `plan`.`id`)
INNER JOIN `dvh`.`issuer`
ON (`plan`.`issuer` = `issuer`.`id`)
WHERE plan.type='UNIT'
AND plan.startDate < NOW()
AND plan.endDate >NOW()
AND plan.resetDay=DAYOFWEEK(NOW())
AND plan.resetHour=tempHour.tzHour
AND account.`active`=1;
solved by moving case to where clause
AND plan.`resetHour` =
CASE
WHEN issuer.`tz`='US/Eastern' THEN HOUR(NOW())+1
WHEN issuer.`tz`='US/Central' THEN HOUR(NOW())
WHEN issuer.`tz`='US/Mountain' THEN HOUR(NOW())-1
WHEN issuer.`tz`='US/Pacific' THEN HOUR(NOW())-2
END

How to use between operator for 2 date input parameters in mysql?

My task is to get the records between 2fromdate and todate(given as a input parameters).
i am not able to use between operator for 2 input parameters...
My query as follows...
DELIMITER $$
CREATE DEFINER=`testrunner`#`%` PROCEDURE `usp_GetAllTranasactions`(pFromDate nvarchar(30),pToDate nvarchar(30),pstatus int)
BEGIN
select
ST.UserID,U.Username,
ST.SubscriptionID,
ST.DateOfSubscription,
SM.SubType,
SM.Details,
ST.Amount,
ST.EndDate,
ST.Status
from tr_t_subscriptiontransactions ST
Join tr_m_users U on U.UserID=ST.UserID
join tr_m_subscription SM on SM.SubscriptionID=ST.SubscriptionID
where **ST.DateOfSubscription between (pFromDate and pToDate) and ST.EndDate
between(pFromDate and pToDate) and ST.Status=pstatus;**
END if;
END
here i don't know how to use between parameters..plz help me..i want to retrive record between fromdate and todate..hope u understand..
Let us assume you want all transactions for the month of June 2014
In your user interface the parameter values are:
from_date = 2014-06-01
to_date = 2014-06-30
But you will evaluate against a transaction date & time. How do you ensure that absolutely every transactions on June 30 - right up to midnight - is included in the results?
Here is how: use 2014-07-01 instead of 2014-06-30, and here is what the query would look like - which does NOT use between!
SELECT
ST.UserID
, U.Username
, ST.SubscriptionID
, ST.DateOfSubscription
, SM.SubType
, SM.Details
, ST.Amount
, ST.EndDate
, ST.Status
FROM tr_t_subscriptiontransactions ST
JOIN tr_m_users U
ON U.UserID = ST.UserID
JOIN tr_m_subscription SM
ON SM.SubscriptionID = ST.SubscriptionID
WHERE (ST.DateOfSubscription >= pFromDate AND ST.DateOfSubscription < pToDate + 1)
AND (ST.EndDate >= pFromDate AND ST.EndDate < pToDate + 1)
AND ST.Status = pstatus
;
AVOID between for date ranges because it INCLUDES both the lower and upper boundary values.
... equivalent to the expression (min <= expr AND expr <= max)
http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#operator_between
What this can lead to is an "anti-pattern" which look like this:
where dt_field between '2014-06-01 00:00:00' and '2014-06-30 23:59:59'
but there are time units smaller than one second, so that approach is imperfect. Don't attempt to overcome the deficiencies of between by adjusting the upper value this way. The simple and more accurate approach is to use >= and < adjusting the upper value by one whole time unit (usually the next day).

getting duplicates after using distinct

I have three tables, one is mapping tale and I am using distinct keyword even though getting duplicate values
SELECT
mer.store_name, mpr.`merchant_code` , mpr.`terminal_num` ,
mpr.`rec_fmt` , mpr.`bat_nbr` , mpr.`Card_Type` ,
mpr.`card_num` , mpr.`transaction_date` , mpr.`settle_date` ,
mpr.`approval_code`, mpr.`intnl_amt` , mpr.`domestic_amt` ,
mpr.`transid` , mpr.`upvalue` , mpr.`merchant_trackid` ,
mpr.`MSF` , mpr.`service_tax` , mpr.`edu_cess` ,
mpr.`net_amount` , mpr.`debit_credit_type`, mpr.`UDF1` ,
mpr.`UDF2` , mpr.`UDF3` , mpr.`UDF4` ,
mpr.`UDF5` , mpr.`seq_num` , mpr.`arn_no`
FROM
`mpr_reports` mpr, merchantreports mer, storename_tid sid
WHERE (
mer.Store_Name = sid.Store_Name
AND sid.terminal_num = mpr.terminal_num
AND mpr.`rec_fmt` = 'cvd'
OR mpr.`rec_fmt` = 'bat'
)
Consider amending the published query to something like this...
SELECT mer.store_name
, mpr.merchant_code
, mpr.terminal_num
, mpr.rec_fmt
, mpr.bat_nbr
, mpr.Card_Type
, mpr.card_num
, mpr.transaction_date
, mpr.settle_date
, mpr.approval_code
, mpr.intnl_amt
, mpr.domestic_amt
, mpr.transid
, mpr.upvalue
, mpr.merchant_trackid
, mpr.MSF
, mpr.service_tax
, mpr.edu_cess
, mpr.net_amount
, mpr.debit_credit_type
, mpr.UDF1
, mpr.UDF2
, mpr.UDF3
, mpr.UDF4
, mpr.UDF5
, mpr.seq_num
, mpr.arn_no
FROM mpr_reports mpr
JOIN storename_tid sid
ON sid.terminal_num = mpr.terminal_num
JOIN merchantreports mer
ON mer.Store_Name = sid.Store_Name
WHERE mpr.rec_fmt IN ('cvd','bat')
;
About SQL joins, you may have some fun here...
It's the kind of thing we learn once, to use during our entire life.
About your specific query, test this first example,
SELECT
mer.store_name,
mpr.`merchant_code`,
mpr.`terminal_num`,
mpr.`rec_fmt`,
mpr.`bat_nbr`,
mpr.`Card_Type`,
mpr.`card_num`,
mpr.`transaction_date`,
mpr.`settle_date`,
mpr.`approval_code`,
mpr.`intnl_amt`,
mpr.`domestic_amt`,
mpr.`transid`,
mpr.`upvalue`,
mpr.`merchant_trackid`,
mpr.`MSF`,
mpr.`service_tax`,
mpr.`edu_cess`,
mpr.`net_amount`,
mpr.`debit_credit_type`,
mpr.`UDF1`,
mpr.`UDF2`,
mpr.`UDF3`,
mpr.`UDF4`,
mpr.`UDF5`,
mpr.`seq_num`,
mpr.`arn_no`
FROM merchantreports mer
INNER JOIN storename_tid sid ON (sid.Store_Name = mer.Store_Name)
INNER JOIN `mpr_reports` mpr ON (sid.terminal_num = mpr.terminal_num)
WHERE mpr.rec_fmt IN ('cvd','bat');
Just a humble advice, consider using foreign keys to join your tables. Indexing columns "Store_Name" and "terminal_num" is also an option, but it'll be rather more efficient to follow what's written in the scriptures (see sec. 5.4.5).