Select changes on days - mysql

I'm trying to make report based on user table like this
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`password` varchar(255) DEFAULT NULL,
`register_date` datetime DEFAULT NULL,
`username` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
)
And I need to show how many users registered in a interval of time. I try this
SELECT COUNT(u.id) as "user_count" FROM user u WHERE u.register_date > '2016-01-01' AND u.register_date < '2016-10-24';
There is a way to make it by day?. i.e. I have initDate and endDate and I get how many users register every day between this days. e.g.
day = 2016-10-23
user_count = 2
day = 2016-10-24
user_count = 5
day = 2016-10-25
user_count = 0

You can use the DATE() function to extract the DATEs from your datetime column, then GROUP BY those dates:
SELECT DATE(u.register_date),COUNT(u.id) as "user_count"
FROM user u
WHERE u.register_date > '2016-01-01'
AND u.register_date < '2016-10-24'
GROUP BY DATE(u.register_date)
ORDER BY DATE(u.register_date);

you can use DATE() function the get the date from the register_date column, and group by it:
SELECT DATE(register_date) as registeringDay ,COUNT(u.id) as "user_count" FROM
user WHERE u.register_date > '2016-01-01' AND u.register_date < '2016-10-24'
GROUP BY registringDay;

Just add the date to the query and GROUP by the date
SELECT COUNT(`id`) as `count`, `register_date`
FROM `user`
WHERE `register_date` BETWEEN '2016-01-01' AND '2016-10-24'
GROUP BY `register_date`;
If the register_date is a DATETIME column
SELECT COUNT(`id`) as `count`, DATE(`register_date`) as `day`
FROM `user`
WHERE `register_date` BETWEEN '2016-01-01' AND '2016-10-24'
GROUP BY DATE(`register_date`);

Related

Mysql SUM by value in column

I have problem to get the proper result.
I have a table with registered time entries by date and user.
I also have a date table, that only consists of dates.
CREATE TABLE `jobbile_job_record` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`note` text,
`time_type` int(11) DEFAULT NULL,
`created_by` varchar(255) DEFAULT NULL,
`created` date DEFAULT NULL,
`jobbile_job_id` int(11) DEFAULT NULL,
`inserted` datetime DEFAULT CURRENT_TIMESTAMP,
`time_registered` decimal(11,2) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1145 DEFAULT CHARSET=latin1;
SET FOREIGN_KEY_CHECKS = 1;
I would like to get a result of
- date
- total time registered
- total time by user (registered)
I use the following query:
SELECT
date.date,
SUM(jobbile_job_record.time_registered) as 'total time',
SUM(jobbile_job_record.time_registered AND `jobbile_job_record`.`created_by` = '5713') as 'User 5713',
SUM(jobbile_job_record.time_registered AND `jobbile_job_record`.`created_by` = '5714') as 'User 5714'
FROM
date
LEFT JOIN jobbile_job_record
ON date.date = jobbile_job_record.created
WHERE
date.date BETWEEN '2019-11-01' AND '2019-11-30'
GROUP BY
date.date
ORDER BY
date.date ASC
Total_time works fine but the two SUM's with users filtered, is not summarized but counted.
Cant I use this method? Thanks!
I guess you need a case statement here -
SELECT
date.date,
SUM(jobbile_job_record.time_registered) as 'total time',
SUM(CASE WHEN `jobbile_job_record`.`created_by` = '5713' THEN jobbile_job_record.time_registered END) as 'User 5713',
SUM(CASE WHEN `jobbile_job_record`.`created_by` = '5714' THEN jobbile_job_record.time_registered END ) as 'User 5714'
FROM date
LEFT JOIN jobbile_job_record ON date.date = jobbile_job_record.created
WHERE date.date BETWEEN '2019-11-01' AND '2019-11-30'
GROUP BY date.date
ORDER BY date.date ASC

Aggregate data use sql

This is the definition of the "exchange" table:
CREATE TABLE `exchange` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`rank` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
`volume` varchar(255) NOT NULL,
`timestamp` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=75032 DEFAULT CHARSET=utf8;
About 209 records will store every 5 minutes.
How can I get this data structure?
rank, name, [volume,...](last 144 value), timestamp
I use this query:
SELECT `volume`
FROM `exchange`
WHERE `exchange`.`name` = 'binance'
ORDER BY `timestamp` DESC
LIMIT 144
Is there better way to get the data once? Thanks.
Frankly, your method might be the best method, particularly if you have an index on (name, timestamp).
You can try:
select e.volume
from exchange e
where e.timestamp >= (select e2.timestamp
from exchange e2
where e2.name = e.name
limit 1 offset 143
);
You can then aggregate the values as:
select e.name, sum(e.volume)
from exchange e
where e.timestamp >= (select e2.timestamp
from exchange e2
where e2.name = e.name
limit 1 offset 143
)
group by e.name;
Note: In MySQL 8+, this is much simpler using row_number():
select name, sum(volume)
from (select e.*,
row_number() over (partition by name order by timestamp desc) as seqnum
from exchange e
) e
where seqnum <= 144
group by name;

Create month and year column to speed up timestamp query

I have a big log table in mariadb/mysql:
CREATE TABLE `logs` (
`id` CHAR(36) NOT NULL,
`user` CHAR(4) NOT, NULL,
`dateCreated` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`dateUpdated` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
I am trying to query logs based on user and date created by month and year:
select * from logs where month(dateCreated) = '9' and year(dateCreated) = '2016' and user = '1234'
Question:
Should I created two columns called month and year, and index the month, year, and user to speed up the query?
You are better off just restructuring your query's criteria to better take advantage of a possible index on the field:
WHERE dateCreated >= '2016-09-01 00:00:00'
AND dateCreated < '2016-10-01 00:00:00'
AND user = '1234'

Latest hour unique entries MySQL

I want to have the latest hour unique entries
This query gives me the latest unique entries (but not of the last hour):
SELECT t1.* FROM allSensors t1
JOIN (SELECT uniqueID, MAX(timestamp) timestamp FROM allSensors GROUP BY uniqueID) t2
ON t1.uniqueID = t2.uniqueID AND t1.timestamp = t2.timestamp;
This query gives me the latest hour entries (but not all of them are unique):
SELECT * FROM allSensors WHERE timeStamp > DATE_SUB(NOW(), INTERVAL 1 HOUR);
How could I get the latest hour latest entries?
How could I get this done with maximum performance??
This will be requested every 5 seconds! And the table has them all
This is the table structure:
CREATE TABLE `allSensors` (
`timeStamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`DeviceID` double DEFAULT NULL,
`UniqueID` double NOT NULL DEFAULT '0',
`DataAge` double DEFAULT NULL,
`Temp` double DEFAULT NULL,
`Light` double DEFAULT NULL,
`Humid` double DEFAULT NULL,
`LeafTemp` double DEFAULT NULL,
`SoilHumid` double DEFAULT NULL,
`SoilEC` double DEFAULT NULL,
`Batt` double DEFAULT NULL,
`SNR` double DEFAULT NULL,
`Ts` double DEFAULT NULL
)
SELECT t1.*
FROM allSensors t1
JOIN
( SELECT uniqueID, MAX(timestamp) timestamp
FROM allSensors
GROUP BY uniqueID
) t2 ON t2.uniqueID = t1.uniqueID
AND t2.timestamp = t1.timestamp;
WHERE t2.timestamp > NOW() - INTERVAL 1 HOUR
That is, get all the last ids, but then throw away the ones that are too old.
You need the composite INDEX(uniqueID, timestamp) (in that order).

sorting with Order By in mysql

I am using mysql as database and i have a table like the one below.
CREATE TABLE IF NOT EXISTS `logins` (
`id` int(255) NOT NULL AUTO_INCREMENT,
`userid` varchar(255) NOT NULL,
`date` varchar(255) NOT NULL,
`status` varchar(255) NOT NULL,
KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=346 ;
I want to sort mysql results with order by.The problem is when i use this sql it takes only the first recod of date. Which is an older date. I want the newest date. last login date of user.
SELECT * FROM `logins` WHERE `status`='valid' GROUP BY `userid` ORDER BY `date` DESC
Any suggestions?
To do this you use a sub query to get the latest record for each user id and then join that to the logins table to get the rest of the details
SELECT logins.*
FROM logins
INNER JOIN
(
SELECT userid, MAX(`date`) AS max_date
FROM `logins`
WHERE `status` = 'valid'
GROUP BY `userid`
) sub0
ON logins.userid = sub0.userid
AND logins.`date` = sub0.max_date
WHERE `status` = 'valid'
You almost had it. Assuming id and userId doesn't evolve from one login to another, asking the MAX date should give you the expected result.
SELECT id, userId, MAX(`date`) AS lastDate, 'valid'
FROM `logins`
WHERE `status`='valid'
GROUP BY `userid`
ORDER BY `lastDate` DESC
Please note that you would need a JOIN if there were data that change between logins in the table.