I need to calculate contribution base on project per developer
Contribution table
-------------------------------------------------------------
| id | projected | developer id | total hours | contribution|
-------------------------------------------------------------
| 1 | 1 | 1 | 25 | |
-------------------------------------------------------------
| 2 | 1 | 2 | 75 | |
-------------------------------------------------------------
| 3 | 2 | 1 | 10 | |
-------------------------------------------------------------
need to update same table with trigger after insert and update
expected result
Contribution table
-------------------------------------------------------------
| id | projected | developer id | total hours | contribution|
-------------------------------------------------------------
| 1 | 1 | 1 | 25 | 25% |
------------------------------------------------------------
| 2 | 1 | 2 | 75 | 75% |
-------------------------------------------------------------
| 3 | 2 | 1 | 10 | 100% |
-------------------------------------------------------------
calculation for the getting contribution
project 1 :
total hours = 25 + 75 = 100
contribution per developer = 25/100*100
= 25%
i need a trigger to get this result: but don't know how to get this
This is my trigger not getting error but contribution calculation not correct
CREATE TRIGGER `update_contribution` AFTER INSERT ON `tasks`
FOR EACH ROW BEGIN
IF NOT EXISTS
(SELECT p_id ,d_id
FROM contribution
WHERE
p_id = NEW.p_id
AND
d_id = NEW.d_id)
THEN
SET #old_total_dev_hours = (SELECT SUM(total_hours)
FROM contribution
WHERE p_id = NEW.p_id
GROUP BY p_id);
SET #total_hours1 = (SELECT (total_hours)
FROM contribution
WHERE d_id = NEW.d_id AND p_id = NEW.p_id
);
SET #dev_con = #total_hours1/#old_total_dev_hours*100 ;
SET #total_hours = new.hours + new.overtime;
INSERT INTO contribution
( p_id,
d_id,
hours,
overtime,
total_hours,
contribution
)
VALUES
(NEW.p_id,
NEW.d_id,
NEW.hours,
NEW.overtime,
#total_hours ,
#dev_con
);
ELSE
UPDATE contribution
SET
hours = hours + NEW.hours ,
overtime = overtime + NEW.overtime,
total_hours = hours + overtime,
contribution = #dev_con
WHERE
p_id = NEW.p_id
AND
d_id = NEW.d_id;
END IF;
END
This is my code in this code other calculation are working fine
contribution is not getting correctly!!
Here's an updated trigger that would replace the one from your previous question. It calculates
both values for the total_hours and contribution percentage.
DELIMITER |
CREATE TRIGGER update_hours AFTER INSERT ON tasks
FOR EACH ROW
BEGIN
SET #old_total_dev_hours = (SELECT SUM(hours + overtime)
FROM contribution
WHERE p_id == new.p_id && d_id == new.d_id
GROUP BY p_id,d_id);
SET #old_total_hours = (SELECT SUM(hours + overtime)
FROM contribution
WHERE p_id == new.p_id
GROUP BY p_id);
SET #total_hours = #old_total_dev_hours + new.hours + new.overtime;
SET #contrib_percent = (#old_total_dev_hours / #old_total_hours) * 100;
INSERT INTO contribution
( p_id,
d_id,
hours,
overtime,
total_hours,
contribution )
VALUES
(
NEW.p_id,
NEW.d_id,
NEW.hours,
NEW.overtime,
#total_hours,
#contrib_percent
);
END|
DELIMITER ;
Assuming tasks logs hours worked by developers on projects then 2 things can happen 1) there is no note that a developer has worked on a project in contribution 2) a developer has worked on a project and the hours he has worked need to updated in contribution. Both cases imply that all developer contributions need to be recalculated on each insert to tasks.
For example
drop table if exists t,contribution;
create table t(id int auto_increment primary key, developerid int, projectid int,hrs_normal int, hrs_overtime int);
create table contribution(id int auto_increment primary key, projectid int,
developerid int, hrs int, contribution decimal (6,3) default 0);
drop trigger if exists t;
delimiter $$
create trigger t after insert on t
for each row
begin
declare totalhours int default 0;
set totalhours = (select ifnull(sum(hrs),0) from contribution where projectid = new.projectid);
set totalhours = totalhours + ifnull(new.hrs_normal,0) + ifnull(new.hrs_overtime,0);
if not exists (select 1 from contribution where projectid = new.projectid and developerid = new.developerid) then
insert into contribution(projectid,developerid,hrs)
values
(new.projectid,new.developerid,ifnull(new.hrs_normal,0) + ifnull(new.hrs_overtime,0)
);
else
update contribution
set hrs = hrs + ifnull(new.hrs_normal,0) + ifnull(new.hrs_overtime,0)
where developerid = new.developerid and projectid = new.projectid;
end if;
update contribution
set contribution = (hrs / totalhours) * 100
where projectid = new.projectid;
end $$
delimiter ;
MariaDB [sandbox]> truncate table t;
Query OK, 0 rows affected (0.28 sec)
MariaDB [sandbox]> truncate table contribution;
Query OK, 0 rows affected (0.25 sec)
MariaDB [sandbox]> select * from t;
Empty set (0.00 sec)
MariaDB [sandbox]> select * from contribution;
Empty set (0.00 sec)
MariaDB [sandbox]>
MariaDB [sandbox]> insert into t (developerid , projectid ,hrs_normal , hrs_overtime )
-> values
-> (1,1,10,0);
Query OK, 1 row affected (0.02 sec)
MariaDB [sandbox]>
MariaDB [sandbox]> select * from t;
+----+-------------+-----------+------------+--------------+
| id | developerid | projectid | hrs_normal | hrs_overtime |
+----+-------------+-----------+------------+--------------+
| 1 | 1 | 1 | 10 | 0 |
+----+-------------+-----------+------------+--------------+
1 row in set (0.00 sec)
MariaDB [sandbox]> select * from contribution;
+----+-----------+-------------+------+--------------+
| id | projectid | developerid | hrs | contribution |
+----+-----------+-------------+------+--------------+
| 1 | 1 | 1 | 10 | 100.000 |
+----+-----------+-------------+------+--------------+
1 row in set (0.00 sec)
MariaDB [sandbox]>
MariaDB [sandbox]> insert into t (developerid , projectid ,hrs_normal , hrs_overtime )
-> values
-> (1,1,10,0),(2,1,30,10);
Query OK, 2 rows affected (0.05 sec)
Records: 2 Duplicates: 0 Warnings: 0
MariaDB [sandbox]>
MariaDB [sandbox]> select * from t;
+----+-------------+-----------+------------+--------------+
| id | developerid | projectid | hrs_normal | hrs_overtime |
+----+-------------+-----------+------------+--------------+
| 1 | 1 | 1 | 10 | 0 |
| 2 | 1 | 1 | 10 | 0 |
| 3 | 2 | 1 | 30 | 10 |
+----+-------------+-----------+------------+--------------+
3 rows in set (0.00 sec)
MariaDB [sandbox]> select * from contribution;
+----+-----------+-------------+------+--------------+
| id | projectid | developerid | hrs | contribution |
+----+-----------+-------------+------+--------------+
| 1 | 1 | 1 | 20 | 33.333 |
| 2 | 1 | 2 | 40 | 66.667 |
+----+-----------+-------------+------+--------------+
2 rows in set (0.00 sec)
MariaDB [sandbox]>
MariaDB [sandbox]> insert into t (developerid , projectid ,hrs_normal , hrs_overtime )
-> values
-> (1,1,10,0),(2,2,30,10);
Query OK, 2 rows affected (0.05 sec)
Records: 2 Duplicates: 0 Warnings: 0
MariaDB [sandbox]>
MariaDB [sandbox]> select * from t;
+----+-------------+-----------+------------+--------------+
| id | developerid | projectid | hrs_normal | hrs_overtime |
+----+-------------+-----------+------------+--------------+
| 1 | 1 | 1 | 10 | 0 |
| 2 | 1 | 1 | 10 | 0 |
| 3 | 2 | 1 | 30 | 10 |
| 4 | 1 | 1 | 10 | 0 |
| 5 | 2 | 2 | 30 | 10 |
+----+-------------+-----------+------------+--------------+
5 rows in set (0.00 sec)
MariaDB [sandbox]> select * from contribution;
+----+-----------+-------------+------+--------------+
| id | projectid | developerid | hrs | contribution |
+----+-----------+-------------+------+--------------+
| 1 | 1 | 1 | 30 | 42.857 |
| 2 | 1 | 2 | 40 | 57.143 |
| 3 | 2 | 2 | 40 | 100.000 |
+----+-----------+-------------+------+--------------+
3 rows in set (0.00 sec)
Note if the business rules are that a developers hours can amended in tasks you will also need and update trigger along the same lines.
Related
this is my code
UPDATE `mytable`
SET `income` = (SELECT sum(`row`) FROM (SELECT * FROM `mytable`)AS mmc WHERE `view_date` = '2018-5-21')
WHERE id = 1 AND view_date = '2018-5-21'
I run this code and it successful, but my data was not update.
You can use the below SQL to update your table properly.
SQL:
update mytable m
join (select id,view_date,sum(row) as row from mytable group by id,view_date) t on (m.id = t.id and m.view_date = t.view_date)
set m.income = t.row
where m.id = 1 and m.view_date = '2018-05-23';
Example are below:
mysql> create table mytable(id int,income int, row int, view_date date);
Query OK, 0 rows affected (0.54 sec)
mysql> insert into mytable values(1,null,230,current_date);
Query OK, 1 row affected (0.12 sec)
mysql> insert into mytable values(1,null,450,current_date);
Query OK, 1 row affected (0.05 sec)
mysql> select * from mytable;
+------+--------+------+------------+
| id | income | row | view_date |
+------+--------+------+------------+
| 1 | NULL | 230 | 2018-05-23 |
| 1 | NULL | 450 | 2018-05-23 |
| 2 | NULL | 800 | 2018-05-23 |
+------+--------+------+------------+
3 rows in set (0.00 sec)
mysql> update mytable m
-> join (select id,view_date,sum(row) as row from mytable group by id,view_date) t on (m.id = t.id and m.view_date = t.view_date)
-> set m.income = t.row
-> where m.id = 1 and m.view_date = '2018-05-23';
Query OK, 2 rows affected (0.13 sec)
Rows matched: 2 Changed: 2 Warnings: 0
mysql> select * from mytable;
+------+--------+------+------------+
| id | income | row | view_date |
+------+--------+------+------------+
| 1 | 680 | 230 | 2018-05-23 |
| 1 | 680 | 450 | 2018-05-23 |
| 2 | NULL | 800 | 2018-05-23 |
+------+--------+------+------------+
3 rows in set (0.00 sec)
I have two tables. First table stk
ITEMID | STOCK
--------------
Test1 | 10
Test2 | 15
Test3 | 12
and second table qty
ITEMID | DOCDATE | QTY
--------------------------
Test1 | 2/28/2017 | 5
Test2 | 2/28/2017 | 8
Test3 | 2/28/2017 | 6
I used this query
select itemid,stock,docdate,qty
from (
select itemid,stock,null docdate,0 qty from stk
union
select itemid,0 stock,docdate,qty from qty
)
group by itemid,stock,docdate,qty
order by 1
Output I get:
ITEMID | STOCK | DOCDATE | QTY
------------------------------
Test1 | 0 |2/28/2017 | 5
Test1 | 10 | | 0
Test2 | 0 |2/28/2017 | 8
Test2 | 15 | | 0
Test3 | 0 |2/28/2017 | 6
Test3 | 12 | | 0
but I want to have this output:
ITEMID | STOCK | DOCDATE | QTY
------------------------------
Test1 | 10 |2/28/2017 | 5
Test2 | 15 |2/28/2017 | 8
Test3 | 12 |2/28/2017 | 6
If you only want to consolidate rows coming from the two different tables then you can use this query:
select itemid, MAX(stock), MAX(docdate), MAX(qty)
from (
select itemid,stock,null docdate,0 qty from stk
union
select itemid,0 stock,docdate,qty from qty
) as t
group by itemid
order by 1
Demo here
If your only goal is to have that output, then you can just do this:
SELECT Q.ItemId, (SELECT S.stock FROM stk S ON S.ItemId = Q.ItemId) AS STOCK, Q.DocDate, Q.Qty FROM qty Q
I am using subqueries to connect the two tables on Id, and then I select the stock from Stk where the ItemId is the same as the ItemId from Qty.
Unions are vertical joins are horizontal. Perhaps something like this is required.
MariaDB [sandbox]> create table stk(ITEMID varchar(10), STOCK int);
Query OK, 0 rows affected (0.20 sec)
MariaDB [sandbox]> insert into stk values
-> ('Test1' , 10),
-> ('Test2' , 15),
-> ('Test3' , 12);
Query OK, 3 rows affected (0.02 sec)
Records: 3 Duplicates: 0 Warnings: 0
MariaDB [sandbox]>
MariaDB [sandbox]> drop table if exists qty;
Query OK, 0 rows affected (0.14 sec)
MariaDB [sandbox]> create table qty(ITEMID varchar(10), DOCDATE varchar(10) , QTY int);
Query OK, 0 rows affected (0.20 sec)
MariaDB [sandbox]> insert into qty values
-> ('Test1' , '2/28/2017' , 5),
-> ('Test2' , '2/28/2017' , 8),
-> ('Test3' , '2/28/2017' , 6),
-> ('Test1' , '3/28/2017' , 7),
-> ('Test2' , '3/28/2017' , 7),
-> ('Test3' , '3/28/2017' , 7);
Query OK, 6 rows affected (0.01 sec)
Records: 6 Duplicates: 0 Warnings: 0
MariaDB [sandbox]>
MariaDB [sandbox]> select s.itemid,s.stock,
-> q.docdate,sum(q.qty) qty
-> from stk s
-> join qty q on q.itemid = s.itemid
-> group by s.itemid,s.stock,q.docdate
-> order by q.docdate, s.itemid,s.stock
->
-> ;
+--------+-------+-----------+------+
| itemid | stock | docdate | qty |
+--------+-------+-----------+------+
| Test1 | 10 | 2/28/2017 | 5 |
| Test2 | 15 | 2/28/2017 | 8 |
| Test3 | 12 | 2/28/2017 | 6 |
| Test1 | 10 | 3/28/2017 | 7 |
| Test2 | 15 | 3/28/2017 | 7 |
| Test3 | 12 | 3/28/2017 | 7 |
+--------+-------+-----------+------+
6 rows in set (0.00 sec)
Use JOIN to get result:
SELECT ITEMID ,STOCK,DOCDATE,QTY
FROM table1
JOIN table2 ON table1.ITEMID = table2.ITEMID
I have a table that look like this:
S_ID | DATE
1 2016-01-01
1 2016-01-02
1 2016-01-02
1 2016-01-05
1 2016-01-05
2 2017-01-02
2 2017-01-04
2 2017-01-04
2 2017-01-04
2 2017-01-04
2 2017-01-05
I am trying, in a single query to have the result below (adding cumulatively the records in time)
DATE | S_ID 1 | S_ID 2
2016-01-01 | 1 | 0
2016-01-02 | 3 | 1
2016-01-03 | 3 | 1
2016-01-04 | 3 | 5
2016-01-05 | 5 | 6
Any suggestions?
Try this using group on date and conditional sum along with user variables to get cumulative sum.
Select date,
#s1 := #s1 + s_id_1 s_id_1,
#s2 := #s2 + s_id_2 s_id_2
From (select
date,
sum(s_id = 1) s_id_1,
sum(s_id = 2) s_id_2
from your_table
group by date
Order by date) t cross join (select #s1 := 0, #s2 :=0 ) t2;
It uses the fact that the true is 1 and false is 0 in mysql
You should better use
select
t.s_ID,
t.`date`,
(SELECT SUM(1) FROM table x WHERE x.`date` <= t.`date` AND x.S_ID = t.S_ID) AS cumulative_sum
from table t
group by s_ID,`date`;
This will not provide your desired result, but a form of the result which works independent of the number of users, while the information stays the same:
s_ID | DATE | cumulative_sum
1 2016-01-01 1
1 2016-01-02 3
1 2016-01-05 5
2 2016-01-02 1
2 2016-01-04 5
2 2016-01-05 6
(If there's no entry for an id/date pair, the count didn't change that day)
You can arrived this with a PREPARED Statement. The first Query will generate a query with all s_id in your table. You only must change YOYOURTABLE to your table name :
see the sample
CONCAT('SELECT `date`,'
,GROUP_CONCAT(f1)
,' FROM YOURTABLE GROUP BY DATE')
INTO #myquery
FROM (
SELECT DISTINCT CONCAT('sum(s_id = ',s_id,') AS sid_',s_id) AS f1
FROM yourtable
) tab1;
-- ONLY for Test to verify the Query
SELECT #myquery;
PREPARE test FROM #myquery;
EXECUTE test;
DEALLOCATE PREPARE test;
sample
mysql> SELECT * FROM yourtable;
+------+------------+
| s_id | date |
+------+------------+
| 1 | 2016-01-01 |
| 1 | 2017-02-02 |
| 2 | 2017-01-05 |
| 4 | 2016-03-04 |
| 7 | 2016-12-12 |
+------+------------+
5 rows in set (0,01 sec)
mysql> SELECT
-> CONCAT('SELECT `date`,'
-> ,GROUP_CONCAT(f1)
-> ,' FROM YOURTABLE GROUP BY DATE')
-> INTO #myquery
-> FROM (
-> SELECT DISTINCT CONCAT('sum(s_id = ',s_id,') AS sid_',s_id) AS f1
-> FROM yourtable
-> ) tab1;
Query OK, 1 row affected (0,01 sec)
mysql> SELECT #myquery;
+----------------------------------------------------------------------------------------------------------------------------------------+
| #myquery |
+----------------------------------------------------------------------------------------------------------------------------------------+
| SELECT `date`,sum(s_id = 1) AS sid_1,sum(s_id = 2) AS sid_2,sum(s_id = 4) AS sid_4,sum(s_id = 7) AS sid_7 FROM YOURTABLE GROUP BY DATE |
+----------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0,00 sec)
mysql> PREPARE test FROM #myquery;
Query OK, 0 rows affected (0,00 sec)
mysql> EXECUTE test;
+------------+-------+-------+-------+-------+
| date | sid_1 | sid_2 | sid_4 | sid_7 |
+------------+-------+-------+-------+-------+
| 2016-01-01 | 1 | 0 | 0 | 0 |
| 2016-03-04 | 0 | 0 | 1 | 0 |
| 2016-12-12 | 0 | 0 | 0 | 1 |
| 2017-01-05 | 0 | 1 | 0 | 0 |
| 2017-02-02 | 1 | 0 | 0 | 0 |
+------------+-------+-------+-------+-------+
5 rows in set (0,00 sec)
mysql> DEALLOCATE PREPARE test;
Query OK, 0 rows affected (0,00 sec)
mysql>
I've got a program at work that exports to CSV but leaves blanks in the most irritable places. I want to view the carrier and destination on the same row and currently the carrier is 1 row above the destination like below:
I have a database that is like the following:
|Key|Carrier ||Destination|
|-------------------------|
| 1 | HULL2 || |
| 2 | || C14A102 |
| 3 | DONC1 || |
| 4 | || D15A012 |
What I want:
|Key|Carrier ||Destination|
|-------------------------|
| 1 | HULL2 || |
| 2 | HULL2 || C14A102 |
| 3 | DONC1 || |
| 4 | DONC1 || D15A012 |
Either that or insert a new column with the information from carrier column.
Sorry if this is confusing its confusing me to explain it!
James
Here is a solution, by cloning another table and then deleting it:
CREATE TABLE t1(Key_id INT PRIMARY KEY, Carrier CHAR(20), Destination CHAR(20));
INSERT INTO t1 VALUES(1, 'HULL2', ''),(2,'','C14A102'),(3,'DONC1',''),(4,'','D15A012');
CREATE TABLE t2 LIKE t1;
INSERT INTO t2 SELECT * FROM t1;
SELECT * FROM t1;
UPDATE t1 SET Carrier =
(
SELECT t2.Carrier
FROM t2
WHERE t2.Key_id < t1.Key_id AND t2.Carrier != ''
ORDER BY t2.Key_id DESC
LIMIT 1
)
WHERE Carrier = '';
SELECT * FROM t1;
DROP TABLE t2;
Output:
mysql> SELECT * FROM t1;
+--------+---------+-------------+
| Key_id | Carrier | Destination |
+--------+---------+-------------+
| 1 | HULL2 | |
| 2 | | C14A102 |
| 3 | DONC1 | |
| 4 | | D15A012 |
+--------+---------+-------------+
4 rows in set (0.00 sec)
mysql> UPDATE t1 SET Carrier =
-> (
-> SELECT t2.Carrier
-> FROM t2
-> WHERE t2.Key_id < t1.Key_id AND t2.Carrier != ''
-> ORDER BY t2.Key_id DESC
-> LIMIT 1
-> )
-> WHERE Carrier = '';
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2 Changed: 2 Warnings: 0
mysql> SELECT * FROM t1;
+--------+---------+-------------+
| Key_id | Carrier | Destination |
+--------+---------+-------------+
| 1 | HULL2 | |
| 2 | HULL2 | C14A102 |
| 3 | DONC1 | |
| 4 | DONC1 | D15A012 |
+--------+---------+-------------+
4 rows in set (0.00 sec)
Assuming that the column 'key' can be trusted in this way, I would update with a self join where the join uses key = key+1, and then make sure it's only affecting even rows.
UPDATE tablename as even_row JOIN tablename as odd_row
ON even_row.Key = odd_row.Key + 1
SET even_row.Carrier = odd_row.Carrier
WHERE odd_row.Key % 2;
I have a table with different values for different countries, for example:
id| country | value
===================
1 | Argelia | 8
2 | USA | 10
1 | China | 12
1 | Italy | 13
I am interested in only one country and the total, but I'm having trouble coming up with a single query to do it. The result of this query for id 1 would be:
id| value_in_Italy | total
==========================
1 | 13 | 33
As you can see, I obtained the value for Italy, and the total value. What kind of query would produce rows like the above for a similar table?
Here is the query you need:
select id,SUM(IF(country='Italy',value,0)) italy_value,SUM(value) id_values
from countrydata where id = 1;
Here is your sample data:
drop database if exists luqita;
create database luqita;
use luqita
create table countrydata
(
id int not null,
country varchar(32),
value int not null
);
insert into countrydata values
(1,'Argelia', 8 ),(2,'USA' , 10 ),
(1,'China' , 12 ),(1,'Italy' , 13 );
select * from countrydata;
Here is your sample data loaded:
mysql> drop database if exists luqita;
Query OK, 1 row affected (0.03 sec)
mysql> create database luqita;
Query OK, 1 row affected (0.02 sec)
mysql> use luqita
Database changed
mysql> create table countrydata
-> (
-> id int not null,
-> country varchar(32),
-> value int not null
-> );
Query OK, 0 rows affected (0.12 sec)
mysql> insert into countrydata values
-> (1,'Argelia', 8 ),(2,'USA' , 10 ),
-> (1,'China' , 12 ),(1,'Italy' , 13 );
Query OK, 4 rows affected (0.05 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> select * from countrydata;
+----+---------+-------+
| id | country | value |
+----+---------+-------+
| 1 | Argelia | 8 |
| 2 | USA | 10 |
| 1 | China | 12 |
| 1 | Italy | 13 |
+----+---------+-------+
4 rows in set (0.00 sec)
mysql>
Here is the proposed query executed:
mysql> select id,SUM(IF(country='Italy',value,0)) italy_value,SUM(value) id_values
-> from countrydata where id = 1;
+----+-------------+-----------+
| id | italy_value | id_values |
+----+-------------+-----------+
| 1 | 13 | 33 |
+----+-------------+-----------+
1 row in set (0.00 sec)
mysql>
Now, if you want to run this query against all rows at the same time, try this all-inclusive query:
select
B.id,
SUM(IF(A.country=B.country,B.value,0)) country_value,
SUM(IF(A.id=B.id,A.value,0)) id_values
from
countrydata A,
countrydata B
group by B.country;
Here is that all-inclusive query execute
mysql> select
-> B.id,
-> SUM(IF(A.country=B.country,B.value,0)) country_value,
-> SUM(IF(A.id=B.id,A.value,0)) id_values
-> from
-> countrydata A,
-> countrydata B
-> group by B.country;
+----+---------------+-----------+
| id | country_value | id_values |
+----+---------------+-----------+
| 1 | 8 | 33 |
| 1 | 12 | 33 |
| 1 | 13 | 33 |
| 2 | 10 | 10 |
+----+---------------+-----------+
4 rows in set (0.00 sec)
mysql>
Give it a Try !!!