I want to select all the rows from table where date different between two row is 4 or less and stop as soon as condition don't match ie diff > 4 in descending order i.e.(from bottom)
caution: once condition is > 4 it will not match further it simply
stops
i.e it will have to select 5,6,7,8,9
I tried using "HAVING", but its slow on big data
Thank you all in advance to helping figure it out.
You can use user-defined variables to track the previous updated_at value (in my example below, in #t) then calculate from that whether the record is desired based on whether the previous record was desired (#b) and, if so, the difference between that last date and the current one:
SELECT id, amount, updated_at
FROM (
SELECT my_table.*,
#b:=IF(#b, DATEDIFF(#t,updated_at)<=4, FALSE) okay,
#t:=updated_at
FROM my_table, (SELECT #b:=TRUE, #t:=MAX(updated_at) FROM my_table) init
ORDER BY updated_at DESC
) t
WHERE okay
ORDER BY updated_at, id
See it on sqlfiddle.
Related
I have a table 'processes' with the following columns :
id
date_creation
date_lastrun
For example I have the following entries:
id;date_creation;date_lastrun
1;2022-01-01 00:00:00;2022-02-01 00:00:00
2;2022-03-01 00:00:00;NULL
I want to select the element with the bigger date in MySQL
I can do
SELECT id, MAX(IFNULL(date_lastrun, date_creation)) as lastdate
FROM processes
It's OK it works but now I want to get the element with the bigger date compared to a specific date time.
I tried :
SELECT id, MAX(IFNULL(date_lastrun, date_creation)) as lastdate
FROM processes
WHERE DATE(lastdate) > "2022-03-01"
but it returns *#1054 - Unknown column 'lastdate' in 'where clause'
SELECT id, MAX(IFNULL(date_lastrun, date_creation)) as lastdate
FROM processes
WHERE DATE(MAX(IFNULL(date_lastrun, date_creation))) > "2022-03-01"
but it returns #1111 - Invalid use of group function
Do you have any idea how to accomplish that?
I hope to return the element with the bigger date compared to a specific date.
Do not use the MAX in the WHERE clause but limit the result to dates bigger than "2022-03-01" and then get the biggest one.
SELECT id, MAX(IFNULL(date_lastrun, date_creation)) as lastdate FROM
processes WHERE DATE(IFNULL(date_lastrun, date_creation)) >
"2022-03-01";
I would prefer GREATEST with COALESCE here:
SELECT id, GREATEST(COALESCE(date_creation,0), COALESCE(date_lastrun,0)) AS lastdate
FROM processes
WHERE GREATEST(COALESCE(date_creation,0), COALESCE(date_lastrun,0)) > "2022-03-01";
MAX is unhandy in this situation due to its limitation to one argument, see also this article: difference max <-> greatest
COALESCE is required in this case because GREATEST is not able to deal with NULL values in MYSQL.
Try out: db<>fiddle
I have a table containing stock market data (open, hi, lo, close prices) but in a random order of date:
Date Open Hi Lo Close
12/10/2019 313.82 314.54 312.81 313.58
11/22/2019 311.09 311.24 309.85 310.96
11/25/2019 311.98 313.37 311.98 313.37
11/26/2019 313.41 314.28 313.06 314.08
11/27/2019 314.61 315.48 314.37 315.48
11/29/2019 314.86 315.13 314.06 314.31
12/2/2019 314.59 314.66 311.17 311.64
12/3/2019 308.65 309.64 307.13 309.55
I have another value in a PHP variable (say $BaseValue),and a start date and end date ($startdt and $enddt).
1) My requirement is to pick-up the value from the HI column, if it exceeds the $BaseValue on the very FIRST date in a chronological order between the given start and end dates.
For example, if the $BaseValue=314, startdt=11/22, enddt=12/2, then I want to retrieve the Date (11/26/19) as it is the earliest date on which the Hi value (314.28) exceeded the $Basevalue within the given date range. The select statement should return both the Hi value (314.28) and the Date (11/26/19).
2) Additionally, I also need to retrieve the HIGHEST value and date from the HI column during the given date duration. In the above scenario, it should return 315.48 and corresponding date 11/27.
The table is NOT in a chronological order - its randomly filled.
I am unable to get the first query at all with the use of MAX function and its various combinations. Makes me wonder if that is possible at all in SQL or not.
While the second is straightforward, I was wondering if it is more efficient and less complex to club the two queries and get the four values in one single shot.
Any ideas on how can I approach the need to fulfill this requirement please?
Thanks
You could use two subqueries for filtering, one per criteria, like:
select t.*
from mytable t
where
t.date = (
select min(t1.date)
from mytable t1
where t1.date between :datedt and :enddt and t1.hi >= :basevalue
)
or t.hi = (
select max(t1.hi)
from mytable t1
where t1.date between datedt and :enddt and t1.hi >= :basevalue
)
Another option is to union two queries with orer by and limit:
(
select t.*
from mytable
where t.date between :datedt and :enddt and t1.hi >= :basevalue
order by t.date
limit 1
)
union
(
select t.*
from mytable t
where t.date between :datedt and :enddt and t1.hi >= :basevalue
order by t.hi desc, t.date
limit 1
)
Please note that both queries do not do exactly the same thing. If there are ties for the highest hi in the period, the first query will return all ties, while the second will pick the earliest one. It's up to you to decide which solution better fits your use case.
I have a MySQL DB where one column is the DATE and the other column is the SIGNAL. Now I would like to calculate the SUM over Signal for 4 days each.
f.e.
SUM(signal over DATE1,DATE2,DATE3,DATE4)
SUM(signal over DATE5,DATE6,DATE7,DATE8)
...
whereas Date_N = successor of DATE_N-1 but need not to be the day before
Moreless the algo should be variable in the days group. 4 ist just an example.
Can anyone here give me an advice how to perform this in MySQL?
I have found this here group by with count, maybe this could be helpful for my issue?
Thanks
Edit: One important note: My date ranges have gaps in it. you see this in the picture below, in the column count(DISTINCT(TradeDate)). It should be always 4 when I have no gaps. But I DO have gaps. But when I sort the date descending, I would like to group the dates together always 4 days, f.e. Group1: 2017-08-22 + 2017-08-21 + 2017-08-20 + 2017-08-19, Group2: 2017-08-18 + 2017-08-17+2017-08-15+2017-08-14, ...
maybe I could map the decending dateranges into a decending integer autoincrement number, then I would have a number without gaps. number1="2017-08-17" number2="2017-08-15" and so on ..
Edit2:
As I see the result from my table with this Query: I might I have double entries for one and the same date. How Can I distinct this date-doubles into only one reprensentative?
SELECT SUM(CondN1),count(id),count(DISTINCT(TradeDate)),min(TradeDate),max(TradeDate) ,min(TO_DAYS(DATE(TradeDate))),id FROM marketstat where Stockplace like '%' GROUP BY TO_DAYS(DATE(TradeDate)) DIV 4 order by TO_DAYS(DATE(TradeDate))
SUM() is a grouping function, so you need to GROUP BY something. That something should change only every four days. Let's start by grouping by one day:
SELECT SUM(signal)
FROM tableName
GROUP BY date
date should really be of type DATE, like you mentioned, not DATETIME or anything else. You could use DATE(date) to convert other date types to dates. Now we need to group by four dates:
SELECT SUM(signal)
FROM tableName
GROUP BY TO_DAYS(date) DIV 4
Note that this will create an arbitary group of four days, if you want control over that you can add a term like this:
SELECT SUM(signal)
FROM tableName
GROUP BY (TO_DAYS(date)+2) DIV 4
In the meantime and with help of KIKO I have found the solution:
I make a temp table with
CREATE TEMPORARY TABLE if not EXISTS tradedatemaptmp (id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY) SELECT Tradedate AS Tradedate, CondN1, CondN2 FROM marketstat WHERE marketstat.Stockplace like 'US' GROUP BY TradeDate ORDER BY TradeDate asc;
and use instead the originate tradedate the now created id in the temp table. So I could manage that - even when I have gaps in the tradedate range, the id in the tmp table has no gaps. And with this I can DIV 4 and get the always the corresponding 4 dates together.
I have a query that shows me the number of calls per day for the last 14 days within my app.
The query:
SELECT count(id) as count, DATE(FROM_UNIXTIME(timestamp)) as date FROM calls GROUP BY DATE(FROM_UNIXTIME(timestamp)) DESC LIMIT 14
On days where there were 0 calls, this query does not show those days. Rather than skip those days, I'd like to have a 0 or NULL in that spot.
Any ideas for how I can achieve this? If you have any questions as to what I'm asking please let me know.
Thanks
I don't believe your query is "skipping over NULL values", as your title suggests. Rather, your data probably looks something like this:
id | timestamp
----+------------
1 | 2014-01-01
2 | 2014-01-02
3 | 2014-01-04
As a result, there are no rows that contain the missing date, so there are no rows to be counted. The answer is that you need to generate a list of all the dates you want and then do a LEFT or RIGHT JOIN to it.
Unfortunately, MySQL doesn't make this as easy as other databases. There doesn't seem to be an effective way of generating a list of anything inline. So you'll need some sort of table.
I think I would create a static table containing a set of integers to be subtracted from the current date. Then you can use this table to generate your list of dates inline and JOIN to it.
CREATE TABLE days_ago_list (days_ago INTEGER);
INSERT INTO days_ago_list VALUES
(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13)
;
Then:
SELECT COUNT(id), list_date
FROM (SELECT SUBDATE(CURDATE(), days_ago) AS list_date FROM days_ago_list) dates_to_list
LEFT JOIN (SELECT id, DATE(FROM_UNIXTIME(timestamp)) call_date FROM calls) calls_with_date
ON calls_with_date.call_date = dates_to_list.list_date
GROUP BY list_date
It is very important that you group by list_date; call_date will be NULL for any days without calls. It is also important to COUNT on id since NULL ids will not be counted. (That ensures you get a correct count of 0 for days with no calls.) If you need to change the dates listed, you simply update the table containing the integer list.
Here is a SQL Fiddle demonstrating this.
Alternatively, if this is for a web application, you could generate the list of dates code side and match up the counts with the dates after the query is done. This would make your web app logic somewhat more complicated, but it would also simplify the query and eliminate the need for the extra table.
create a table that contains a row for each date you want to ensure is in the results, left outer join with results of your current query, use temp table's date, count of above query and 0 if that count is null
I would like to know if this is possible using a mysql query:
I have a table called updates.
In the updates table I have 2 columns, id and timestamp.
I have 5 rows each with the same id but with different date timestamps. An example of this timestamp would be the value: 2012-08-04 23:14:09.
I would like to select only the most recent timestamp value out of the 5 results. This could also be explained by saying that I would like to select the value that is closest to the current date and time. How could I do this?
SELECT id, timestamp FROM updates ORDER BY timestamp DESC LIMIT 1
have you tried SELECT MAX(timestamp) ?