Min value from Database in MySQL - php

Am trying to find the min value from past 30 days, in my table there is one entry for every day, am using this query
SELECT MIN(low), date, low
FROM historical_data
WHERE name = 'bitcoin'
ORDER BY STR_TO_DATE(date,'%d-%m-%Y') DESC
LIMIT 7
But this value not returing the correct value. The structure of my table is
Table structure
And table data which is store is like this
Table data style
Now what i need is to get the minimum low value. But my query not working it give me wrong value which even did not exist in table as well.
Updates:
Here is my updated Table Structure.
enter image description here
And here is my data in this table which look like this
enter image description here
Now if you look at the data, i want to check the name of token omisego and fatch the low value from past 7 days which will be from 2017-12-25 to 2017-12-19
and in this cast the low value is 9.67, but my current query and the query suggested by my some member did not brings the right answer.
Update 2:
http://rextester.com/TDBSV28042
Here it is, basically i have more then 1400 coins and token historical data, which means that there will me more then 1400 entries for same date like 2017-12-25 but having different name, total i have more then 650000 records. so every date have many entries with different names.

To get the lowest row per group you could use following
SELECT a.*
FROM historical_data a
LEFT JOIN historical_data b ON a.name = b.name
AND a.low > b.low
WHERE b.name IS NULL
AND DATE(a.date) >= '2017-12-19' AND DATE(a.date) <= '2017-12-25'
AND a.name = 'omisego'
or
SELECT a.*
FROM historical_data a
JOIN (
SELECT name,MIN(low) low
FROM historical_data
GROUP BY name
) b USING(name,low)
WHERE DATE(a.date) >= '2017-12-19' AND DATE(a.date) <= '2017-12-25'
AND a.name = 'omisego'
DEMO
For last 30 day of 7 days or n days you could write above query as
SELECT a.*, DATE(a.`date`)
FROM historical_data2 a
LEFT JOIN historical_data2 b ON a.name = b.name
AND DATE(b.`date`) >= CURRENT_DATE() - INTERVAL 30 DAY
AND DATE(b.`date`) <= CURRENT_DATE()
AND a.low > b.low
WHERE b.name IS NULL
AND a.name = 'omisego'
AND DATE(a.`date`) >= CURRENT_DATE() - INTERVAL 30 DAY
AND DATE(a.`date`) <= CURRENT_DATE()
;
DEMO
But note it may return more than one records where low value is same, to choose 1 row among these you have specify another criteria to on different attribute

Consider grouping the same and running the clauses
SELECT name, date, MIN(low)
FROM historical_data
GROUP BY name
HAVING name = 'bitcoin'
AND STR_TO_DATE(date, '%M %d,%Y') > DATE_SUB(NOW(), INTERVAL 30 DAY);
Given the structure, the above query should get you your results.

// Try this code ..
SELECT MIN(`date`) AS date1,low
FROM historical_data
WHERE `date` BETWEEN now() - interval 1 month
AND now() ORDER by low ASC;

Related

get monthly record of employees in one query using mysql

I am using this query for getting monthly record of employees those are present and absent.
However i am getting the result for one employee by using this query but for all employees it doesn't seems to work.
SELECT
m.emp_id AS `Empid`,
d.dt AS `AbsentDate`,
(CASE
WHEN p.punch_status IS NULL THEN 'A'
ELSE p.punch_status
END) s
FROM
(SELECT
DATE(t.added_date) AS dt
FROM
pmc_attendance t
WHERE
DATE(t.added_date) >= '2018-08-01'
AND DATE(t.added_date) < DATE_ADD('2018-08-31', INTERVAL 1 DAY)
GROUP BY DATE(t.added_date)
ORDER BY DATE(t.added_date)) d
CROSS JOIN
tbl_admin_users m
LEFT JOIN
pmc_attendance p ON DATE(p.added_date) >= d.dt
AND DATE(p.added_date) < d.dt + INTERVAL 1 DAY
AND p.emp_id = m.emp_id
WHERE
p.emp_id IS NULL AND m.emp_id = '000838'
GROUP BY d.dt
ORDER BY m.emp_id , d.dt
I am using two tables 1. tbl_admin_users- employee data stored 2. pmc_attendance- present records of employees.
in query if i have passed the and m.emp_id='000838' it works fines but i want to show all records for all employees. any suggestions how i can optimize this query.
There are a couple of ways to structure this query. I can see what yuo are doing, and I think the only issue is with your group by clauses. You dont need them as everything should be distinct. Your status will always be 'A' as you are only getting rows where there is no punch for the employee for the day, so you can also take out the case statement.
SELECT
m.emp_id AS Empid,
d.dt AS AbsentDate,
'A' s
FROM
(
SELECT distinct DATE(t.added_date) AS dt
FROM pmc_attendance t
WHERE t.added_date >= '2018-08-01' AND DATE(t.added_date) < DATE_ADD('2018-08-31', INTERVAL 1 DAY)
) d
CROSS JOIN tbl_admin_users m
LEFT JOIN pmc_attendance p ON p.emp_id = m.emp_id and DATE(p.added_date) >= d.dt AND DATE(p.added_date) < d.dt + INTERVAL 1 DAY
WHERE p.emp_id IS NULL
ORDER BY m.emp_id , d.dt
If you want to include both present and absent, you would need to put your case statement back in, and remove your check WHERE p.emp_id IS NULL
If you have multiple punchs for the day, then you need to resolve it down to a single entry with a MIN/MAX so you only get one row per person per day, and add back in your group by Emp_ID, d.dt

Manipulate Date, new day starts at specific time SQL

I'm developping a dashboard for a restaurant/bar.
I want to manipulate the date , so for example:
If they sell something at 02 january ,01h30 .
This amount should be added to the amount of the 1st January and not to the amount of the 2nd January.
So basically on the next day from 00h00 until 03h59, the amount that they sell, should be added to the previous date.
At the moment my SQL query just displays both dates but I want it grouped in 1 date. If this isn't possible with SQL, I have my dashboard in PHP, so I can eventually manipulate it in PHP if anyone could provide me that info.
My query
select CONVERT(CHAR(10), receiptdatetime, 120), datename(DW,receiptdatetime),
sum(rld.NetAmount), count(rl.ReceiptId)
from receipt r, receiptline rl, vw_ReceiptLineDetail rld
where rl.ReceiptId = r.ReceiptId and
rl.ModifiedKind != 300
and rld.ReceiptLineId = rl.ReceiptLineId and
receiptdatetime <= DATEADD(HOUR,4,DATEADD(DAY,1, '01/01/2018'))
and receiptdatetime >= DATEADD(HOUR,4,'01/01/2018')
group by CONVERT(CHAR(10), receiptdatetime, 120), datename(DW, receiptdatetime)
order by 1
So the current output is like this (shortened):
Date Amount
1 01/01/2018 100
2 02/01/2018 20
But I want it like this
Date Amount
1 01/01/2018 120
You can use this query and work with dates as you want
here is you first query that gives you that result
select CONVERT(CHAR(10), receiptdatetime, 120), datename(DW,receiptdatetime),
sum(rld.NetAmount), count(rl.ReceiptId)
from receipt r, receiptline rl, vw_ReceiptLineDetail rld
where rl.ReceiptId = r.ReceiptId and
rl.ModifiedKind != 300
and rld.ReceiptLineId = rl.ReceiptLineId and
receiptdatetime <= DATEADD(HOUR,4,DATEADD(DAY,1, '01/01/2018'))
and receiptdatetime >= DATEADD(HOUR,4,'01/01/2018')
group by CONVERT(CHAR(10), receiptdatetime, 120), datename(DW, receiptdatetime)
order by 1
you can use this result as a first select with this :
With CTE as
(
select CONVERT(CHAR(10), receiptdatetime, 120), datename(DW,receiptdatetime),
sum(rld.NetAmount), count(rl.ReceiptId)
from receipt r, receiptline rl, vw_ReceiptLineDetail rld
where rl.ReceiptId = r.ReceiptId and
rl.ModifiedKind != 300
and rld.ReceiptLineId = rl.ReceiptLineId and
receiptdatetime <= DATEADD(HOUR,4,DATEADD(DAY,1, '01/01/2018'))
and receiptdatetime >= DATEADD(HOUR,4,'01/01/2018')
group by CONVERT(CHAR(10), receiptdatetime, 120), datename(DW, receiptdatetime)
order by 1
)
so like this you have the result stored on a table called CTE
NOw i don't have the data so i will create my owne Variable table to store the result that you got from first query you can use your CTE tabale as a source instade of #Table
Declare #Table table (
id int,
dates date,
amout int
)
insert into #Table
select 1 , '2018-01-01' , 100 union
select 2 , '2018-01-02' , 20 union
select 2 , '2018-02-02' , 200 union
select 2 , '2018-01-03' , 20 union
select 2 , '2018-01-04' , 20
now to get the Amout with the result that you want here is the query to use
you do the select from CTE :
select sum(amout) as Amout from #Table
where dates between '2018-01-01' and '2018-01-04'
Result :
Amout
160
now you will use that result and union it with you table to get the ID that you want and the date that you want and i thing you should convert the last table date into nvarchar(50) so you will have this result
1- when you do the whole month
ID Date Amout
1 2018-01 160
2- when you do by timeframe
ID Date Amout
1 '2018-01-01 2018-01-14' 160
you can start by hardcoding the ID and Date as you want and union is to the result Amout that you get from the query
or you can do variables to configure the ID and date that you want to show with the Amout
thanks if you ahve any questions i'm here i have done the test on my local and it works and i hope that this is what you need :)
use the :
;With CTE as ( select (RowCount() Over (Partition by Date order by id) row_count) , date, amout
from tables and where conditions
Then on the select Add the amount that have the same Date into each others
selecting from CTE table
if you want to Add the Amounts of all day on the same month then select Only Year and Month on Date column then do the partition by over this Date

MySQL query rows with defined date interval

I have no idea how to solve the following problem: I have several rows in my database with one timestamp per row. Now I would like to filter all rows for entries until the date interval for any two dates is bigger than 30 days. I have no defined date interval for specific dates, like between 12/01/2017 and 11/01/2017, that would be easy, even for me. All I know is that the timestamp interval from one row to the next row (query must be sorted by timestamp desc) must not be bigger than 30 days.
Please see my db at http://sqlfiddle.com/#!9/55a521/2
In this case the last entry shown should be the one with id 65404844. I would appreciate if you might give me a small hint for this.
Thank you very much!
You can use this query to build a filter.
SELECT
t.id,
from_unixtime(timestamp)
, IF(#pt < timestamp - 30*24*60*60, 1, 0) AS filter
, #pt := timestamp
FROM
t
, (SELECT #pt := MIN(timestamp) FROM t) v
ORDER BY timestamp
see it working live in an sqlfiddle
Important here is to order by timestamp. Then you initialize the #pt variable with the lowest value. Another important thing is to have the select clause in the right order.
First you compare the current record with the variable in the IF() function. Then you assign the current record to the variable. This way when the next row is evaluated, the variable still holds the value of the previous row in the IF() function.
To get the rows you want, use above query in a subquery to filter.
SELECT id, ts FROM (
SELECT
t.id,
from_unixtime(timestamp) as ts
, IF(#pt < timestamp - 30*24*60*60, 1, 0) AS filter
, #pt := timestamp
FROM
t
, (SELECT #pt := MIN(timestamp) FROM t) v
ORDER BY timestamp
) sq
WHERE sq.filter = 1
This filters out the rows that have a more than 30 days difference from the previous rows. (1st solution) - only works if the id column has consecutive values
SELECT t.id, t.timestamp, DATEDIFF(FROM_UNIXTIME(t1.timestamp), FROM_UNIXTIME(t.timestamp)) AS days_diff
FROM tbl t
LEFT JOIN tbl t1
ON t.id = t1.id + 1
HAVING days_diff <= 30
ORDER BY t.timestamp DESC;
This filters all the results that are within 30 days of each of the other entries.
SELECT *
FROM tbl t
WHERE EXISTS (
SELECT id
FROM tbl t1
WHERE DATEDIFF(FROM_UNIXTIME(t1.timestamp), FROM_UNIXTIME(t.timestamp)) < 30
AND t1.id <> t.id
)
ORDER BY t.timestamp desc;

MySQL - Getting data for week ahead

I have this sql query:
SELECT
"bookings"."customerID",
"bookings"."arrivalDate",
"bookings"."leavingDate",
"bookings"."bookingID",
"bookings"."pickup",
"bookings"."dropoff",
"bookings"."locationID",
"locations"."locationName",
"customers"."customerName"
FROM
"bookings"
LEFT JOIN "customers" ON
"bookings"."customerID" = "customers"."customerID"
LEFT JOIN "locations" ON
"bookings"."locationID" = "locations"."locationID"
WHERE (
"bookings"."arrivalDate" BETWEEN '2014-11-15' AND '2014-11-22'
)
What i'm hoping to get is all the bookings for the week ahead. Sorted by oldest first. Just cant get it to work!
SELECT
b.customerID,
b.arrivalDate,
b.leavingDate,
b.bookingID,
b.pickup,
b.dropoff,
b.locationID,
l.locationName,
c.customerName
FROM
bookings b
LEFT JOIN customers c
ON b.customerID = c.customerID
LEFT JOIN locations l
ON b.locationID = l.locationID
WHERE
b.arrivalDate > curdate()
AND b.arrivalDate <= date_add( curdate(), INTERVAL 7 DAY )
order by
b.leavingDate DESC
I updated to utilize aliases vs long table name references. Also, the where clause to make use of the current date and 7 days forward to get the week ahead so it is not hard-referenced. You could additionally adjust in case you wanted the query always to be based on a Sat or Sun of a given week.
As for the sorting by the "oldest" first... oldest in what way... just change the order by clause. I am GUESSING your intent was on the date leaving out... So by that column DESCENDING would put the oldest LEAVING item at the top of the list.

MySQL Query Problem with INTERVAL, need 0 if no data provided

i have the following statement:
SELECT
count(rs.rsc_id) as counter
FROM shots as rs
where rsc_rs_id = 345354
AND YEAR(rs.timestamp) = YEAR(DATE_SUB(CURDATE(), INTERVAL 6 MONTH))
GROUP BY DATE_FORMAT(rs.timestamp,'%Y%m')
rs.timestamp is a unix timestamp
Output would be like for each row / month a numeric like '28'
It Works fine, but if i have inconsistent data, like only for the past three month (not for all six month), i get no return from my Database. I would like to have every time there is not data for this month, 0 returned...
any suggestion?
i thought about some case statements, but this seems not so good...
thanks!!
For only 6 months, a date table seems unnecessary, although this looks complicated (it really isn't!)
SELECT DATE_FORMAT(N.PivotDate,'%Y%m'), count(rs.rsc_id) as counter
FROM (
select ADDDATE(CURDATE(), INTERVAL N MONTH) PivotDate
FROM (
select 0 N union all
select 1 union all
select 2 union all
select 3 union all
select 4 union all
select 5 union all
select 6) N) N
LEFT JOIN shots as rs
ON rsc_rs_id = 345354
AND DATE_FORMAT(N.PivotDate,'%Y%m')=DATE_FORMAT(FROM_UNIXTIME(rs.timestamp),'%Y%m')
GROUP BY DATE_FORMAT(N.PivotDate,'%Y%m')
In such cases it's common to use a table of dates with all dates (e.g. from 1/1/1970 to 31/12/2999) and LEFT JOIN your data to that table.
See an example in the answer here: mysql joins tables creating missing dates
If you create a dates table you can use:
SELECT
DATE_FORMAT(d.date,'%Y%m') AS `month`, count(rs.rsc_id) AS `counter`
FROM dates d
LEFT JOIN shots as rs
ON d.date = FROM_UNIXTIME(rs.timestamp)
AND rs.rsc_rs_id = 345354
WHERE d.date > DATE_SUB(CURDATE(), INTERVAL 5 MONTH)
AND d.date < CURDATE()
GROUP BY DATE_FORMAT(d.date,'%Y%m');

Categories