MySQL sum of hours between multiple dates - mysql

I have two tables projects and project_hours, with a one to many (one project, many hours).
Here are my two tables:
CREATE TABLE `projects` (
`project_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`client_id` int(10) unsigned NOT NULL,
`project_name` char(50) NOT NULL,
`project_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`project_id`),
KEY `project_owner` (`client_id`),
CONSTRAINT `projects_ibfk_1` FOREIGN KEY (`client_id`) REFERENCES `clients` (`client_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
CREATE TABLE `project_hours` (
`hours_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`project_id` int(10) unsigned NOT NULL,
`start_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`end_time` datetime NOT NULL,
PRIMARY KEY (`hours_id`),
KEY `project_id` (`project_id`),
CONSTRAINT `project_hours_ibfk_1` FOREIGN KEY (`project_id`) REFERENCES `projects` (`project_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
What I would like to do is select all projects, and get a sum of the hours, so I have a final list of project with total hours. So if I have 1 projects, 2 records in project_hours, I would like to get 1 rows back, and not 2 rows.
Here is what I have tried. What I get is 2 rows, and each one's time span is less than 1 hour, so current_hours is showing as 0. What can I do to sum the two rows up? to get 1.50 or something along those lines?
select *, datediff(start_time, end_time) * 60 as current_hours from projects
left join project_hours using(project_id)
where client_id = 2

Here we go! This seems to do what I was looking for:
select *, sum(time_to_sec(timediff(end_time, start_time))) / 60 / 60 as current_hours from projects
left join project_hours using(project_id)
where client_id = 2
group by project_id

Related

How to get two sums from two tables in one output?

I have two tables:
Receive_Amount_Details for crediting amount from the construction site owner, and
SitewiseEmployee for debiting the amount to pay the laborer.
For every single Date, which is present in both tables, I want to:
sum all of the Amount_Received from Receive_Amount_Details as Total_Receive_Amount_from_siteowner, and
sum all of the Amount from SitewiseEmployee as Total_Amount_Payed_to_Labour
column on output table.
Both tables have the Date column, but I want a single Date column in the output.
If any single day amount is not received and labour was paid, it should be in the output table, and also if any single day amount was received but not paid for labour, then also it needs to be present in the output table.
CREATE TABLE `Receive_Amount_Details` (
`Id` int(10) NOT NULL AUTO_INCREMENT,
`SiteId` int(5) NOT NULL,
`Amount_Received` int(10) NOT NULL,
`Date` date NOT NULL,
PRIMARY KEY (`Id`),
KEY `SiteId` (`SiteId`),
CONSTRAINT `Receive_Amount_Details_ibfk_1` FOREIGN KEY (`SiteId`)
REFERENCES `SiteList` (`Id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
and
CREATE TABLE `SitewiseEmployee` (
`Id` int(10) NOT NULL AUTO_INCREMENT,
`SiteId` int(5) NOT NULL,
`EmployeeId` int(10) NOT NULL,
`Amount` varchar(10) DEFAULT NULL,
`Date` date NOT NULL,
PRIMARY KEY (`Id`),
KEY `SiteId` (`SiteId`),
KEY `EmployeeId` (`EmployeeId`),
CONSTRAINT `SitewiseEmployee_ibfk_1` FOREIGN KEY (`SiteId`)
REFERENCES `SiteList` (`Id`),
CONSTRAINT `SitewiseEmployee_ibfk_2` FOREIGN KEY (`EmployeeId`)
REFERENCES `Employee` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1
Assuming that you may have dates in the one table that are not present in the other, and vice versa, you would need to perform a full outer join. MySql does not have such a join type, but you can achieve it with a union:
select `Date`,
sum(Amount_Received) as Sum_Amount_Received,
sum(Amount) as Sum_Amount
from (
select `Date`, Amount_Received, 0 as Amount
from Receive_Amount_Details
union
select `Date`, 0, Amount
from SitewiseEmployee
) as dates
group by `Date`;

MySQL move rows from one table to another by condition

We have a MySQL database of users, their sold and purchased products. We need to move inactive users who have not logged-in from last 3 years and never purchased or sold anything on our website to another table. Each table has millions of entries.
This is a table for sold items. Around 40m entries;
CREATE TABLE `sold` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`uid` int(10) unsigned NOT NULL,
`item` bigint(20) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `uid` (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
This is a table for purchased items. Around 6m entries;
CREATE TABLE `purchased` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`uid` int(10) unsigned NOT NULL,
`item` bigint(20) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `uid` (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
This is a user table, around 17m entries;
CREATE TABLE `users` (
`uid` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(32) DEFAULT '',
`email` varchar(64) DEFAULT NULL,
`lastlogin` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`uid`),
UNIQUE KEY `email_index` (`email`),
KEY `lastlogin` (`lastlogin`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
This is the table where we need to move inactive users to
CREATE TABLE `inactiveusers` (
`uid` int(10) unsigned NOT NULL,
`name` varchar(32) DEFAULT '',
`email` varchar(64) DEFAULT NULL,
`lastlogin` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`uid`),
UNIQUE KEY `email_index` (`email`),
KEY `lastlogin` (`lastlogin`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Any suggestions on how to achieve this with minimum downtime?
#Yumoji, I guess your probelm is How to calculate the last three 3 years of any activity. Right?
So, if that is the case then you should add a "created_at" column in your DB tables.
Now, after you add a created_at column in your tables you can easily calculate last three years activity.
Here it is-
SELECT uid FROM sold AND purchased WHERE sold.created_at>DATE_SUB(NOW(), INTERVAL 3 YEAR) OR purchased.created_at>DATE_SUB(NOW(), INTERVAL 3 YEAR);
from this query you get the user ids, Then -
INSERT INTO inactiveusers select * from users where uid = 'the user ids u get';
DELETE FROM users where uid = 'the user ids u get';
I hope it solves problem. Cheers.

Trouble with Date fields & Combining data from 2 tables

I'm having a MySQL Database, created using the following code (sure there are other tables too, but they're not relevant as per this specific question) :
DROP TABLE IF EXISTS `Jeweller`.`Product_sales`;
CREATE TABLE `Jeweller`.`Product_sales` (
`sale_id` int(11) unsigned NOT NULL,
`product_id` int(11) NOT NULL,
`quantity` int(11),
`value` float,
FOREIGN KEY (`sale_id`) REFERENCES `Jeweller`.`Sales`(`id`),
FOREIGN KEY (`product_id`) REFERENCES `Jeweller`.`Products`(`id`),
CHECK (`quantity`>0),
CHECK (`value`>0)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `Jeweller`.`Products`;
CREATE TABLE `Jeweller`.`Products` (
`id` int(11) unsigned NOT NULL,
`product_category_id` int(11) NOT NULL,
`seller_id` int(11) NOT NULL,
`name` varchar(100) NOT NULL,
`description` text,
PRIMARY KEY (`id`),
FOREIGN KEY (`product_category_id`) REFERENCES `Jeweller`.`Product_categories`(`id`),
FOREIGN KEY (`seller_id`) REFERENCES `Jeweller`.`Sellers`(`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `Jeweller`.`Sales`;
CREATE TABLE `Jeweller`.`Sales` (
`id` int(11) unsigned NOT NULL,
`date` date DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
How would you go about finding :
Total earnings (quantity*value) per month (in 2013 - or any specific year for that matter)
I started by trying to get the month out of a DATE field (using DATEPART) but I'm already into trouble...
So, any ideas?
P.S.
I'm not a guru with SQL
The above is just an example, and not the exact code
SELECT MONTH(s.date) month, SUM(p.quantity * p.value)
FROM Jeweller.Sales s
JOIN Jeweller.Product_sales p ON p.sale_id = s.id
WHERE s.date >= '2013-01-01' AND s.date < '2014-01-01'
GROUP BY month
Note that if the date range spans multiple years, you will need to group on both year and month.

MySQL link table with extra fields creates cartesian product

I'm trying to build an app that besides recording number of sales also maintains the history between a supervisor and his/her team.
CREATE TABLE `emp` (
`id` int(11) NOT NULL,
`nombre` varchar(45) NOT NULL,
`apellido` varchar(45) NOT NULL,
`tl_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `tlFK_idx` (`tl_id`),
CONSTRAINT `tlFK` FOREIGN KEY (`tl_id`) REFERENCES `emp` (`id`)
CREATE TABLE `super` (
`id` int(11) NOT NULL,
`nombre` varchar(45) NOT NULL,
`apellido` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
)
CREATE TABLE `emp_super` (
`emp_id` int(11) NOT NULL,
`super_id` int(11) NOT NULL,
`fecha` date NOT NULL,
PRIMARY KEY (`emp_id`,`super_id`,`fecha`),
KEY `empFK_idx` (`emp_id`),
KEY `superFK_idx` (`super_id`),
CONSTRAINT `empsuperFK` FOREIGN KEY (`emp_id`) REFERENCES `emp` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `super_empFK` FOREIGN KEY (`super_id`) REFERENCES `super` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
)
As you can see, the table emp_super is the link table with the exception of having a date field.
emp_id super_id fecha
101863 101404 2012-10-15
101863 101503 2012-10-01
102403 101404 2012-10-15
102403 101503 2012-10-01
103052 101404 2012-10-15
103052 101503 2012-10-01
103718 101404 2012-10-15
103718 101503 2012-10-01
The key is to keep a record of when a supervisor was assigned to a group, so that when there is any change, the new supervisor would not inherit his group's performance under the previous leader.
I've been working on a query to extract the sales made by a particular group but I immediately noticed that even though I think I'm making all the right connections, I receive a Cartesian product.
Here's the sales table:
CREATE TABLE `sales` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`sale_date` date NOT NULL,
`product_id` int(11) NOT NULL,
`emp_id` int(11) NOT NULL,
`qty` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `empFK_idx` (`emp_id`),
KEY `campaignFK_idx` (`product_id`),
CONSTRAINT `empFK` FOREIGN KEY (`emp_id`) REFERENCES `emp_super` (`emp_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `productFK` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
)
Normally, when dealing with dates, I try and limit the dates to the main table my data is coming from but in this case I need to also take into account the dates for the employee-supervisor relationship.
My query so far is this:
SELECT s.sale_date,su.id,concat_ws(' ',su.nombre,su.apellido), p.name,e.id,concat_ws(' ',e.nombre,e.apellido), s.qty
from tracker.emp e, tracker.products p, tracker.sales s,tracker.super su, tracker.emp_super es
where e.id = es.emp_id
and su.id = es.super_id
and s.product_id = p.id
and e.id = s.emp_id
and s.sale_date between '2012-10-01' and '2012-10-15'
and es.fecha between '2012-10-01' and '2012-10-15'
order by su.id,p.name,e.id;
If I reduce the dates to the 14, then I receive the correct result because the other supervisor did not join until the 15. Has anyone ever encountered this business requirement: to maintain a record of leadership so that a new leader does not inherit his predecessors achievements or mistakes?
Thank you for any suggestions you might have.
You need to take account of when the supervisory role ended.
This will give you that but I suspect that it will not be very efficient.
SELECT e1.emp_id
,e1.super_id
,e1.fecha
,MIN(DATEADD(DAY, -1, e2.fecha)) AS end
FROM emp_super e1
INNER JOIN
emp_super e2 ON e1.emp_id=e2.emp_id
AND
e1.fecha<e2.fecha
GROUP BY e1.emp_id
,e1.super_id
,e1.fecha
Perhaps an end column on the link table updated by a TRIGGER would be better?

Nested "select ... in" performance is slow - how to fix?

Here I have a simple join query. If first two queries get results, the whole query can be done in 0.3 secs, but if the first 2 select doesn't fetch any result, the whole query will cost more than half a minute. What causes this difference? How to fix this problem and improve the performance?
SELECT * FROM music WHERE id IN
(
SELECT id FROM music_tag_map WHERE tag_id IN
(
SELECT id FROM tag WHERE content ='xxx'
)
)
LIMIT 10
Here's the table structure:
CREATE TABLE `tag` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`content` varchar(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `index2` (`content`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `music` (
`id` int(7) NOT NULL AUTO_INCREMENT,
`name` varchar(500) NOT NULL,
`othername` varchar(200) DEFAULT NULL,
`player` varchar(3000) DEFAULT NULL,
`genre` varchar(100) DEFAULT NULL,
`sounds` text,
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `player` (`player`(255)),
KEY `name` (`othername`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `music_tag_map` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`music_id` int(7) NOT NULL,
`tag_id` int(7) NOT NULL,
`times` int(11) DEFAULT '1',
PRIMARY KEY (`id`),
KEY `music_id` (`music_id`),
KEY `tag_id` (`tag_id`),
CONSTRAINT `music_tag_map_ibfk_1` FOREIGN KEY (`id`) REFERENCES `music` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `music_tag_map_ibfk_2` FOREIGN KEY (`tag_id`) REFERENCES `tag` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
There are no joins in that query; there are two sub-selects.
A joined query would be:
SELECT *
FROM music
JOIN music_tag_map ON music.id=music_tag_map.id
JOIN tag ON music_tag_map.tag_id=tag.id
WHERE tag.content = ?
LIMIT 10;
An EXPLAIN applied to each will show you why the join performs better than the sub-select: the sub-select will scan the entire music table (the primary query), while the optimizer can pick the order of tables to scan for the joins, allowing MySQL to use indices to get only the needed rows from all the tables.