Latest hour unique entries MySQL - 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).

Related

how insert registers of today from another table mysql

I'm trying to count the records in my "records" table and insert in results table but I just want to count today's records.
Below you will see some alternatives that I tried (I'm using MySQL), but I keep getting this error:
You have a syntax error in your SQL next to '' on line 2
INSERT INTO results (Data,total)
VALUES (now(), (SELECT COUNT(*) FROM records WHERE Data = now());
This SQL also causes an error:
INSERT INTO results (Data, total)
VALUES (now(), (SELECT COUNT(record.ID) AS day FROM record
WHERE date(Data) = date(date_sub(now(), interval 0 day));
and then
INSERT INTO resultS (Data,total)
VALUES (now(), (SELECT COUNT(*) FROM records
WHERE Data >= DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY));
And yet another attempt:
INSERT INTO results (Data, Total)
VALUES (now(), (SELECT COUNT(*) FROM records
WHERE DATE(Data)= CURRENT_DATE() - INTERVAL 1 DAY));
This is my sql config man:
CREATE TABLE `records`
(
`ID` char(23) NOT NULL,
`Name` varchar(255) NOT NULL,
`Total` int(255) NOT NULL,
`Data` date NOT NULL,
`QrCode` varchar(255) NOT NULL,
`City` varchar(255) NOT NULL,
`Device` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `results`
(
`id` int(11) NOT NULL,
`total` int(11) NOT NULL,
`Data` date DEFAULT NULL,
`grown` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
You have defined grown column as not null so you cannot put there NULL.
My query works :
INSERT INTO results
VALUES (1, (SELECT COUNT(1) FROM records WHERE Data= now()), now(), 1);
You should define default value for grown column. Same situation you have with column id. You should define sequence for column id:
id NOT NULL AUTO_INCREMENT;
INSERT INTO results (Data, total)
SELECT CURRENT_DATE(), COUNT(*)
FROM records
WHERE DATE(Data) = CURRENT_DATE();

Convert MySQL query to Laravel query builder code

I am working with agricultural product management system. I have a question regarding a MySQL query. I would like to know how to create the same query using Laravel query builder:
SELECT
vegitables.name, vegitables.image, vegitables.catagory,
AVG(price_wholesale),
SUM(CASE WHEN rank = 1 THEN price_wholesale ELSE 0 END) today,
SUM(CASE WHEN rank = 2 THEN price_wholesale ELSE 0 END) yesterday
FROM (
SELECT
veg_id, price_wholesale, price_date,
RANK() OVER (PARTITION BY veg_id ORDER BY price_date DESC) as rank
FROM old_veg_prices
) p
INNER JOIN vegitables ON p.veg_id = vegitables.id
WHERE rank in (1,2)
GROUP BY veg_id
This Output result get when run query in database:
Following two table are used to get today price yesterday price and price average get from each product.
CREATE TABLE `vegitables` (
`id` bigint(20) UNSIGNED NOT NULL,
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`image` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`catagory` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`total_area` int(11) NOT NULL COMMENT 'Total area of culativate in Sri Lanka (Ha)',
`total_producation` int(11) NOT NULL COMMENT 'Total production particular product(mt)',
`annual_crop_count` int(11) NOT NULL COMMENT 'how many time can crop pre year',
`short_dis` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
ALTER TABLE `vegitables`
ADD PRIMARY KEY (`id`);
ALTER TABLE `vegitables`
MODIFY `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
COMMIT;
CREATE TABLE `old_veg_prices` (
`id` bigint(20) UNSIGNED NOT NULL,
`veg_id` int(11) NOT NULL,
`price_wholesale` double(8,2) NOT NULL,
`price_retial` double(8,2) NOT NULL,
`price_location` int(11) NOT NULL,
`price_date` date NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
ALTER TABLE `old_veg_prices`
ADD PRIMARY KEY (`id`);
ALTER TABLE `old_veg_prices`
MODIFY `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=6;
COMMIT;
I try this site to convert to MySQL query to query builder code. But it show some error's could find it out. Any Way i want to run this code in Laravel with any method??
Your query will not return the data for yesterday and today; it will return the data for two most recent dates (e.g. if today is 2021-11-01 and most recent two dates for for carrots are 2021-10-25 and 2021-10-20 it will use those two dates). Using RANK() ... IN (1, 2) is also incorrect because it can return ranks such as 1 followed by 3 instead of 2.
To get today and yesterday prices you don't need window functions. Just use appropriate where clause and conditional aggregation:
SELECT vegitables.name
, vegitables.image
, vegitables.catagory
, AVG(old_veg_prices.price_wholesale) AS avgwholesale
, SUM(CASE WHEN old_veg_prices.price_date = CURRENT_DATE - INTERVAL 1 DAY THEN old_veg_prices.price_wholesale END) AS yesterday
, SUM(CASE WHEN old_veg_prices.price_date = CURRENT_DATE THEN old_veg_prices.price_wholesale END) AS today
FROM vegitables
INNER JOIN old_veg_prices ON vegitables.id = old_veg_prices.veg_id
WHERE old_veg_prices.price_date IN (CURRENT_DATE - INTERVAL 1 DAY, CURRENT_DATE)
GROUP BY vegitables.id -- other columns from vegitables table are functionally dependent on primary key
The Laravel equivalent would be:
DB::table('vegitables')
->Join('old_veg_prices', 'old_veg_prices.veg_id', '=', 'vegitables.id')
->whereRaw('old_veg_prices.price_date IN (CURRENT_DATE - INTERVAL 1 DAY, CURRENT_DATE)')
->select(
'vegitables.name',
'vegitables.image',
'vegitables.catagory',
DB::raw('AVG(old_veg_prices.price_wholesale) AS avgwholesale'),
DB::raw('SUM(CASE WHEN old_veg_prices.price_date = CURRENT_DATE - INTERVAL 1 DAY THEN old_veg_prices.price_wholesale END) AS yesterday'),
DB::raw('SUM(CASE WHEN old_veg_prices.price_date = CURRENT_DATE THEN old_veg_prices.price_wholesale END) AS today')
)
->groupBy(
'vegitables.id',
'vegitables.name',
'vegitables.image',
'vegitables.catagory'
)
->get();
"Query builder" features of abstraction products often leave out some possible SQL constructs. I recommend you abandon the goal of reverse engineering SQL back to Laravel and simply perform the "raw" query.
Also...
rank() OVER (PARTITION BY veg_id ORDER BY price_date DESC) as rank
requires MySQL 8.0 (MariaDB 10.2).
And suggest you avoid the alias "rank" since that is identical to the name of a function.

MySQL get row when certain limit has been reached

I'm getting an headache of solving the following problem.
We are looking for a query where it retrieves a the data when the SUM(price_total) reached a certain level grouped by type. Table structures are as followed:
CREATE TABLE `Table1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`Date` datetime DEFAULT NULL,
`type` int(11) DEFAULT NULL,
`price_total` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=latin1;
Data
INSERT INTO `Table1` (`id`, `Date`, `type`, `price_total`)
VALUES
(1,'2013-02-01 00:00:00',1,5),
(2,'2013-02-01 00:00:00',2,15),
(3,'2013-02-02 00:00:00',1,25),
(4,'2013-02-03 00:00:00',3,5),
(5,'2013-02-04 00:00:00',4,15),
(6,'2013-03-05 00:00:00',1,20),
(7,'2013-08-07 00:00:00',4,15);
Example outcome for threshold 15, in chronological order.
Type 1: 2013-02-02 00:00:00 Because here it came above 15. (15+5)
Type 2: 2013-02-01 00:00:00
Type 3: n/a SUM(price_total) < 15
Type 4: 2013-02-04 00:00:00
To sum up. I want to know the date that they crossed the threshold. Price total should be summed up in chronological order.
Here's a simple, self explanatory query:
select type, min(date) as date
from (
select t1.type, t1.date, sum(t2.price_total) as total
from table1 t1
join table1 t2
on t2.type = t1.type
and t2.date <= t1.date
group by t1.type, t1.date
having total >= 15
) sub
group by type
Demo: http://rextester.com/GMAK8269

Select changes on days

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`);

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'