how to select two different date in mysql? - mysql

I'm new to database and MySQL. I'm developing a stock tracking software backend with MySQL database. I have a problem in the MYSQL query.
I need to track price change for a certain period. how can I select two different column and row based on date. for example I need MYSQL to return 'open' value from date '2019-02-27' and 'close' value from date '2019-03-01';
and calculate the % differences in between two value(which is Decimal).
Is it possible to do this kind of query in MYSQL or I should write program which send two query. one to get 'open' from '2019-02-27' and other to get 'close' from '2019-03-01'.
here is the SQL fiddle for my problem http://sqlfiddle.com/#!9/eb23e3/6
here is any example table
symbol | date | open | close | low | high
----------------------------------------------------
HCL | 2019-02-27 | 36.00 | 38.00 | 34.00 | 40.00
HCL | 2019-02-28 | 37.00 | 39.00 | 36.00 | 41.00
HCL | 2019-03-01 | 38.00 | 42.00 | 37.00 | 46.00
how can I get 'open' from date '2019-02-27' AND 'close' from date '2019-03-01'
and then calculated the % difference like (2019-02-27) 'open' value is 36.00 and (2019-03-01) 'close' value is 42.00 so the % percentage difference is +16.6%.

With this you get the 3 needed columns:
select t.*,
concat(
case when t.close > t.open then '+' else '' end,
truncate(100.0 * (t.close - t.open) / t.open, 1)
) percentdif
from (
select
(select open from dailyprice where date = '2019-02-27') open,
(select close from dailyprice where date = '2019-03-01') close
) t
See the demo

I suggest to run two different queries and then calculate the difference of the returned values

Related

Calculate difference between min and max for each group [duplicate]

This question already has answers here:
Calculate difference between min and max for each column only if higher then 0
(3 answers)
Why Mysql's Group By and Oracle's Group by behaviours are different
(3 answers)
Closed 1 year ago.
I've got table with football odds and I need to calculate difference between the odds where the updated value was MIN and where updated value was MAX for each fixture and for each of the selected markets. In the output I need to get the difference and the odds where the value in updated column was MAX
I would like to accomplish that with one query.
The table looks like that
| fix_id| odds| odds_type | updated|
|:-----:| ---:| ---------:| ------:|
| 120 | 1.80| home | 160 |
| 120 | 1.40| home | 150 |
| 120 | 2.00| home | 140 |
| 188 | 1.00| u/o | 200 |
| 121 | 1.60| away | 160 |
| 121 | 1.40| away | 150 |
| 121 | 1.10| away | 140 |
What I'm expecting to get
| fix_id| odds| odds_type | updated| diff|
| -----:| ---:| ---------:| ------:|----:|
| 120 | 1.80| home | 160 | -0.2|
| 121 | 1.60| away | 160 | 0.5|
The code I was trying and it seems to get the difference between the MIN and MAX correct but returns random odds instead off the MAX and I'm not sure if it would be efficient to calculate differences for hundreds of fixtures.
SELECT a.*, MAX(a.odds) - MIN(a.odds) difference FROM odds_table a
where odds_type in ('home','away') group by odds_type,fix_id
I used to calculate the differences in php and then use them to update different table inside the loop but there is a 1000's of odds so it takes ages to process.
P.S I'm using MySQL 5.7
If you were using a more recent version of Mysql (which I'd highly recommend) this could be achieved using row_number and CTEs in a much more elegant way however the following should achieve what you are after, and does not rely on MySQLs unique grouping ablities:
SELECT o.fix_id,
o.odds_type,
SUM(case when max_values.fix_id IS NOT NULL then odds end) AS odds,
SUM(max_updated) AS updated,
cast(SUM(case when max_values.fix_id IS NOT NULL then odds end) - SUM(case when min_values.fix_id IS NOT NULL then odds END) AS decimal(10,2)) AS difference
FROM odds_table o
LEFT JOIN (
SELECT fix_id, MAX(updated) AS max_updated
FROM odds_table
GROUP BY fix_id
) AS max_values ON o.fix_id = max_values.fix_id AND o.updated = max_values.max_updated
LEFT JOIN (
SELECT fix_id, MIN(updated) AS min_updated
FROM odds_table
GROUP BY fix_id
) AS min_values ON o.fix_id = min_values.fix_id AND o.updated = min_values.min_updated
WHERE odds_type in ('home','away')
GROUP BY o.fix_id

MySQL select avg reading every hour even if there is no reading

I'm having a hard time making a MySQL statement from a Postgres one for a project we are migrating. I won't give the exact use case since it's pretty involved, but I can create a simple comparable situation.
We have a graphing tool that needs somewhat raw output for our data in hourly intervals. In Postgres, the SQL would generate a series for the date and hour over a time span, then it would join a query against that for the average where that date an hour existed. We were able to get for example the average sales by hour, even if that number is 0.
Here's a table example:
Sales
datetime | sale
2017-12-05 08:34:00 | 10
2017-12-05 08:52:00 | 20
2017-12-05 09:15:00 | 5
2017-12-05 10:22:00 | 10
2017-12-05 10:49:00 | 10
Where something like
SELECT DATE_FORMAT(s.datetime,'%Y%m%d%H') as "byhour", AVG(s.sale) as "avg sales" FROM sales s GROUP BY byhour
would produce
byhour | avg sales
2017120508 | 10
2017120509 | 5
2017120510 | 10
I'd like something that gives me the last 24 hours, even the 0/NULL values like
byhour | avg sales
2017120501 | null
2017120502 | null
2017120503 | null
2017120504 | null
2017120505 | null
2017120506 | null
2017120507 | null
2017120508 | 10
2017120509 | 5
2017120510 | 10
...
2017120600 | null
Does anyone have any ideas how I could do this in MySQL?
Join the result on a table that you know contains all the desired hours
someting like this:
SELECT
* FROM (
SELECT
DATE_FORMAT(s.datetime, '%Y%m%d%H') AS 'byhour'
FROM
table_that_has_hours
GROUP BY byhour) hours LEFT OUTER JOIN (
SELECT
DATE_FORMAT(s.datetime, '%Y%m%d%H') AS 'byhour',
AVG(s.sale) AS 'avg sales'
FROM
sales s
GROUP BY byhour) your_stuff ON your_stuff.byhour = hours.by_hours
if you don't have a table like that you can create one.
like this:
CREATE TABLE ref (h INT);
INSERT INTO ref (h)
-> VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),
-> (12),(13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23)
and then you can just DATE_FORMAT(date(now()),'%Y%m%d%H') to the values

How to add two kind of values from the same columns in a table

I have a table called Expenses in MySQL data store. The table structure and data are given below:
---------------
|YEAR|Expenses|
|----|--------|
|2015|503K |
|----|--------|
|2015|406K |
|----|--------|
|2015|1.2M |
|----|--------|
|2016|700K |
|----|--------|
|2016|900K |
|----|--------|
|2016|3.2M |
|----|--------|
|2016|4.7M |
---------------
I need to take the sum of all values ending with 'K', group the result by year and multiply the result with 1000. Likewise, I need to take the sum of all the values ending with 'M', group the result by year and multiply the result with 1000000. Finally, I need to add the results of both K values and M values and obtain the total expenses for every year. My final table should look like this in two different formats:
---------------
|YEAR|Expenses|
|----|--------|
|2015|2109000 |
|----|--------|
|2016|9500000 |
|----|--------|
or
---------------
|YEAR|Expenses|
|----|--------|
|2015|2.1M |
|----|--------|
|2016|9.5M |
|----|--------|
Any suggestions or guidelines?
Even if mysql does allow you to add values ending with non-numeric characters I would suggest you don't get into the habit of thinking that other sql dialects do the same.
select year,
cast(
sum(case when instr(expenses,'k') > 0.0 then
cast(replace(expenses,'k','') as decimal(15,2)) * 1000
when instr(expenses,'m') > 0.0 then
cast(replace(expenses,'m','') as decimal(15,2)) * 1000000
end
)
as int ) en
from t
group by year
Result
+------+---------+
| year | en |
+------+---------+
| 2015 | 2109000 |
| 2016 | 9500000 |
+------+---------+
2 rows in set, 7 warnings (0.00 sec)
You can use the following:
SELECT
year,
sum(
CASE
WHEN expenses like '%K' then expenses*1000
WHEN expenses like '%M' then expenses*1000000
END) AS expenses
FROM
table_name
GROUP BY
year
ORDER BY
year;
Hope it helps. Interesting that mysql lets you add values ending with non-numeric characters. Didn't know that one.

MySQL how to present day results (starting value, total change and day-end value from table

I have this table (have a look on SQLFiddle)
In previous steps the record number has been determined and the values for "PrevVal" and "NewVal" have been calculated.
The record's end value ("NewVal"), becomes the next record's starting value ("PrevVal")
I would like to condense the table in such a way that there is only one record per day, containing:
the date starting value "StartOfDay",
the total change during the day "TotalChange" and
the resulting day-end value "EndOfDay"
The desired result can be seen in the demo table "ChangesPerDayCondensed"
Who can help me solve this (a stored procedure is OK).
Thnx
I am a little confused whey the record numbers are going the opposite way. But neverthless you could solve this by evaluating the starting value and sum of mutations separatately and then adding them all to come up with ending value..
Ordering the results descending as the record number again needs to be lower for a higher date.
insert into ChangesPerDayCondensed
select #recrd:=#recrd+1, a.MyDate, b.PrevVal, a.Mutation, b.PrevVal+a.Mutation
from
(select MyDate, sum(Mutation) as Mutation from MutationsPerDay group by MyDate) a,
(select b.MyDate, b.PrevVal from (select MyDate, max(RecNo) as RecNo from MutationsPerDay group by MyDate) a, MutationsPerDay b where a.RecNo = b.RecNo) b,
(select #recrd:=0) c
where a.MyDate = b.MyDate order by MyDate desc;
I'd do it this way:
First create a lookup for each day (find first and lasts ReqNo) and then join two times to the Daily table and calculate the changes:
SELECT first_.MyDate,
first_.PrevVal AS StartOfDay,
last_.NewVal AS EndOfDay,
(last_.NewVal - first_.PrevVal) AS TotalChange
FROM
(SELECT mpd1.MyDate,
max(mpd1.RecNo) AS first_rec_no,
min(mpd1.RecNo) AS last_rec_no
FROM MutationsPerDay mpd1
GROUP BY MyDate) AS lo
JOIN MutationsPerDay AS first_ ON lo.first_rec_no = first_.RecNo
JOIN MutationsPerDay AS last_ ON lo.last_rec_no = last_.RecNo
Explanation:
What you actually want is:
For every day the first and the last value (and the difference).
So what you need to find first is for every date the id of the first and the last value:
SELECT mpd1.MyDate,
max(mpd1.RecNo) AS first_rec_no,
min(mpd1.RecNo) AS last_rec_no
FROM MutationsPerDay mpd1
GROUP BY MyDate
----------------------------------------------------
| MyDate | first_rec_no | last_rec_no |
----------------------------------------------------
| 2016-12-05 00:00:00 | 16 | 13 |
| 2016-12-07 00:00:00 | 12 | 12 |
| 2016-12-12 00:00:00 | 11 | 8 |
| 2016-12-14 00:00:00 | 7 | 7 |
| 2016-12-20 00:00:00 | 6 | 6 |
| 2016-12-21 00:00:00 | 5 | 4 |
| 2016-12-28 00:00:00 | 3 | 3 |
| 2016-12-29 00:00:00 | 2 | 2 |
| 2016-12-30 00:00:00 | 1 | 1 |
----------------------------------------------------
Then you can use these first and last id's to find the corresponding values in the source table. For example for the 2016-12-21 you'd get the rows with the id's first: 5 and last: 4
The PrevVal record no 5 represents the first value you have seen at this day and NewVal in record no 4 represents the last value you have seen at this day. If you subtract them you'll get the change for this day.
I hope this clarifies the methodology a bit.

can't calculate proper total hours?

I have following fields
Date InTime OutTime Status
2016-01-04 10:19:00 05:10:00 Out
I tried below query
SELECT sum(time_to_sec(timediff(CONCAT(`TodayDate`,' ',`OutTime`),CONCAT(`TodayDate`,' ',`InTime`)))/ 3600) as total FROM `wp_ag_punch` where UserId=$userid and TodayDate='$today'
but it's give -5.15 hr.
please help me to solve it
You are using wrong system architecture rather then using two fileds for date and time use only one which will work for all your cases
Please use following structure
DatetimeIn (timestamp) DatetimeOut (timestamp) Status
1451912118 1451912140 Out
now directly do
Select DatetimeIn - DatetimeOut as output
that will give you output in seconds
output
------
22
You should be storing the datetime fields as DateTime datatype, instead of trying to keep the two fields as separate. So for you initial DB setup, you would instead want:
| DateTimeIn | DateTimeOut | Status |
|---------------------|---------------------|--------|
| 2016-01-04 10:19:00 | 2016-01-04 05:10:00 | Out |
Which, in turn, can be queried for the difference between the two timestamps using something like:
SELECT TIMESTAMPDIFF(MINUTE,DateTimeIn,DateTimeOut) AS total_minutes
which would return:
| total_minutes |
|---------------|
| -309 |
Assuming that the later time is actually at 5 PM, the data could be expressed as:
| DateTimeIn | DateTimeOut | Status |
|---------------------|---------------------|--------|
| 2016-01-04 10:19:00 | 2016-01-04 17:10:00 | Out |
and the query:
SELECT TIMESTAMPDIFF(MINUTE,DateTimeIn,DateTimeOut) AS total_minutes
would return :
| total_minutes |
|---------------|
| 411 |
Or, if you wanted the time-span in hours, you only need to change that part of query like:
SELECT TIMESTAMPDIFF(HOUR,DateTimeIn,DateTimeOut) AS total_hours
to get the result :
| total_hours |
|---------------|
| 6 |
Actually either your out time should be '17:10:00' or date should be different as per mysql time format.
Further after seeing your record format, you don't need to concat date with time, instead you just do your calculation on time as per below-
SELECT SUM(TIME_TO_SEC(TIMEDIFF(`OutTime`,`InTime`)))/ 3600 AS total FROM `wp_ag_punch` WHERE UserId=$userid AND TodayDate='$today'
Try below query:
SELECT (time_to_sec(timediff(OutTime,Intime)) / 3600) as total FROM `wp_ag_punch` where UserId=$userid and TodayDate='$today'
I solved it.just change the 12 hour format to 24 hour format and use below query.
SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(OutTime,InTime)))) AS totals FROM wp_ag_punch where UserId=$userid and TodayDate='$today'