Select based on numeric difference - mysql

I have a database table that holds order information and saves the current gold price (world price) automatically at the time of entry.
If I look back on the table, and the saved gold price has a difference with the current gold price of +100, O want to show that in a report.
How would I write the MySQL query to do this? I know how to do datediffs but not numeric values.
Example:
select * from table where saved_price < current_price - 100
Is there a better way to do this?

Use Abs if the sign of the difference doesn't matter:
select * from table where abs(saved_price - current_price) > 100
If the sign is interesting, your suggested approach is fine. I'd write it like this, but use the way you think is the most read- and understandable:
select * from table where (current_price - saved_price) >= 100

Related

Calculate Sum of Mean and Std dev in sql query on single column

I am having table name as "Table1" in mysql.I have to find Sum of Mean and Std dev on column "Open".I did it easily using python but I am unable to do it using sql.
Select * from BANKNIFTY_cal_spread;
Date Current Next difference
2021-09-03 00:00:00 36914.8 37043.95 129.14999999999418
2021-09-06 00:00:00 36734 36869.15 135.15000000000146
2021-09-07 00:00:00 36572.9 36710.65 137.75
2021-09-08 00:00:00 36945 37065 120
2021-09-09 00:00:00 36770 36895.1 125.09999999999854
Python Code-
nf_fut_mean = round(df['difference'].mean())
print(f"NF Future Mean: {nf_fut_mean}")
nf_fut_std = round(df['difference'].std())
print(f"NF Future Standard Deviation: {nf_fut_std}")
upper_range = round((nf_fut_mean + nf_fut_std))
lower_range = round((nf_fut_mean - nf_fut_std))
I search for Sql solution but I didn't get it. I tried building query but it's not showing correct results in query builder in grafana alerting.
Now I added Mean column ,std dev column , upper_range and lower_range column using python dataframe and pushed to mysql table.
#Booboo,
After removing Date from SQL Query, it's showing correct results in two columns- average + std_deviation and average - std_deviation.
select average + std_deviation, average - std_deviation from (
select avg(difference) as average, stddev_pop(difference) as std_deviation from BANKNIFTY_cal_spread
) sq
It looks as though the sample you're using for the aggregations for MEAN, STDDEV, etc is the entire table - in which case you have to drop the DATE field from the query's result set.
You could also establish the baseline query using a CTE (Common Table Expression) using a WITH statement instead of a subquery, and then apply the subsequent processing:
WITH BN_CTE AS
(
select avg(difference) as average, stddev_pop(difference) as std_deviation from BANKNIFTY_cal_spread
)
select average + std_deviation, average - std_deviation from BN_CTE;
With the data you posted having only a single Open column value for any given Date column value, you standard deviation should be 0 (and the average just that single value).
I am having difficulty in understanding your SQL since I cannot see how it relates to finding the sum (and presumably the difference, which you also seem to want) of the average and standard deviation of column Open in table Table1. If I just go by your English-language description of what you are trying to do and your definition of table Table1, then the following should work. Note that since we want both the sum and difference of two values, which are not trivial to calculate, we should calculate those two values only once:
select Date, average + std_deviation, average - std_deviation from (
select Date, avg(Open) as average, stddev_pop(Open) as std_deviation from Table1
group by Date
) sq
order by Date
Note that I am using column aliases in the subquery that do not conflict with built-in MySQL function names.
SQL does not allow both calculating something in the SELECT clause and using it. (Yes, #variables allow in limited cases; but that won't work for aggregates in the way hinted in the Question.)
Either repeat the expressions:
SELECT average(difference) AS mean,
average(difference) + stddev_pop(difference) AS "mean-sigma",
average(difference) - stddev_pop(difference) AS "mean+sigma"
FROM BANKNIFTY_cal_spread;
Or use a subquery to call the functions only once:
SELECT mean, mean-sigma, mean+sigma
FROM ( SELECT
average(difference) AS mean,
stddev_pop(difference) AS sigma
FROM BANKNIFTY_cal_spread
) AS x;
I expect the timings to be similar.
And, as already mentioned, avoid using aliases that are identical to function names, etc.

MySQL - group by interval query optimisation

Some background first. We have a MySQL database with a "live currency" table. We use an API to pull the latest currency values for different currencies, every 5 seconds. The table currently has over 8 million rows.
Structure of the table is as follows:
id (INT 11 PK)
currency (VARCHAR 8)
value (DECIMAL
timestamp (TIMESTAMP)
Now we are trying to use this table to plot the data on a graph. We are going to have various different graphs, e.g: Live, Hourly, Daily, Weekly, Monthly.
I'm having a bit of trouble with the query. Using the Weekly graph as an example, I want to output data from the last 7 days, in 15 minute intervals. So here is how I have attempted it:
SELECT *
FROM currency_data
WHERE ((currency = 'GBP')) AND (timestamp > '2017-09-20 12:29:09')
GROUP BY UNIX_TIMESTAMP(timestamp) DIV (15 * 60)
ORDER BY id DESC
This outputs the data I want, but the query is extremely slow. I have a feeling the GROUP BY clause is the cause.
Also BTW I have switched off the sql mode 'ONLY_FULL_GROUP_BY' as it was forcing me to group by id as well, which was returning incorrect results.
Does anyone know of a better way of doing this query which will reduce the time taken to run the query?
You may want to create summary tables for each of the graphs you want to do.
If your data really is coming every 5 seconds, you can attempt something like:
SELECT *
FROM currency_data cd
WHERE currency = 'GBP' AND
timestamp > '2017-09-20 12:29:09' AND
UNIX_TIMESTAMP(timestamp) MOD (15 * 60) BETWEEN 0 AND 4
ORDER BY id DESC;
For both this query and your original query, you want an index on currency_data(currency, timestamp, id).

Price computation cache solution

The price calculations for the product I rent out is very complicated, and basically signature for it looks like this:
price = f( from_date, to_date, x ) - i.e dependent on 3 parameters: from_date, to_date, x, where from_date and to_date are dates, and x is a numeric (int) value in range from 1 to 10.
f - is the complicated underlying function.
Main constraints:
1) from_date accept values [ today; today + 1 year ]
2) to_date > from_date
3) |(to_date - from_date)| takes values from [1..365]
I use MySQL as my main storage and I have around 50,000 items.
And I would like to build a search page, where you could filter or sort by price (after entering dates; x defaults to 1 if omitted).
I understand that this cannot be converted into MySQL query, because it is too complicated (and even if was possible, it would be very slow and inefficient).
I thought that maybe I could use a key-value storage like redis or memcache to pre-calculate price values for all possible date ranges, store them there, and invalidate if needed (and that will not happen often).
But, using some basic math, I figured out that using this approach I would need at most 33,580,500,000 keys: (366 * 367 / 2) * 10 * 50,000
And my question is - I'm I thinking in right direction?
If yes - are there any efficient solutions (in terms of # of keys, memory footprint and scalability) to this problem?
Thanks in advance!

MySql Query for prices with three or more decimal places

a customer has a database with all of his products (about 10k). Now he asked me to send him a list with all products which have a price with three or more decimal places (<--- I hope this is the right term. I mean all the numbers after the dot).
I can't think of a query which could to this. Any suggestions?
I am fairly new to MySql that's probably the main problem :-)
Thanks in advance!
Mark
PS: The customer doesn't want to have the numbers rounded - at least not now :-)
Mark, try something like this.
SELECT field_name FROM table_name WHERE LENGTH(SUBSTR(column_name,INSTR(column_name,"."))) >3
This solution also filters decimal places ending with 0, i.e. 123.340 and 123.300 get filtered, as they are essentialy 123.34 and 123.3 respectively.
select
your_column
from
your_table
where your_column * 100 - floor(your_column * 100) > 0

Calculate average date difference between records in MS Access

I have a list on when items have been handed out. The table has the following structure:
primary key - autonumber itemname
itemid - number
datehandedout - date/time
I want to calculate the average length of time between when one object is given out and the next one is given out. There will be a number of different items for which the average time between handouts needs to be listed for.
So something like (pseudocode):
average( [thisrecord]![datehandedout] - [lastrecord]![datehandedout] )
Any help will be much appreciated.
This is a very slow query:
SELECT Avg(DateDiff("h",[datehandedout],(
SELECT TOP 1 datehandedout
FROM tbl tx
WHERE tx.datehandedout > t.datehandedout))) AS Difference
FROM tbl AS t
Add another Where statement to limit the number of records returned when you test, for example:
WHERE Year([datehandedout])=2010