I am trying to do transformation on a table in Mysql. I can't figure out how to do it. Could anyone tell me how to do it? The input and output is given. I would like to know how it is done?
Input table
+-------------+------------+------------------+-------------------+
| Employee_ID | Start_Date | Termination_Date | Performance_Level |
+-------------+------------+------------------+-------------------+
| 1 | 1/1/2007 | 3/1/2007 | Low |
| 2 | 6/5/2004 | Null | Medium |
| 3 | 4/3/2003 | Null | High |
| 4 | 9/1/2002 | 4/15/2007 | Medium |
| 5 | 4/6/2007 | 11/1/2007 | Low |
| 6 | 7/1/2007 | Null | High |
| 7 | 3/2/2005 | 8/1/2007 | Low |
+-------------+------------+------------------+-------------------+
Ouput Table
+---------+-----------------------------------+-----------------+-------------------+----------------+
| Period | Total_Employees_at_end_of_quarter | High_Performers | Medium_Performers | Low_Performers |
+---------+-----------------------------------+-----------------+-------------------+----------------+
| Q1-2007 | 4 | 1 | 2 | 1 |
| Q2-2007 | 4 | 1 | 1 | 2 |
| Q3-2007 | 4 | 2 | 1 | 1 |
| Q4-2007 | 3 | 2 | 1 | 0 |
+---------+-----------------------------------+-----------------+-------------------+----------------+
This is what I tried
select * from emp
where date(sdate)< date'2007-04-01' and (date(tdate)> date'2007-03-31' or tdate is null);
select * from emp
where date(sdate)< date'2007-07-01' and (date(tdate)> date'2007-06-30' or tdate is null);
select * from emp
where date(sdate)< date'2007-010-01' and (date(tdate)> date'2007-09-30' or tdate is null);
select * from emp
where date(sdate)< date'2008-01-01' and (date(tdate)> date'2007-12-31' or tdate is null);
I have the individual queries but I want a single query which will give the outputs.
The approach taken below is to create a driver table for each quarter, with information about the year and quarter. This is then joined to the employee table, using a non-equijoin. Employees who start in or before the quarter and end after the quarter are active at the end of quarter.
It uses one trick for the date comparisons, which is to convert the year-quarter combination into a quarter count, by multiplying the year by 4 and adding the quarter. This is a convenience for simplifying the date comparisons.
select driver.qtryr, count(*) as TotalPerformers,
sum(Performance_level = 'High') as HighPerformers,
sum(Performance_level = 'Medium') as MediumPerformers,
sum(Performance_level = 'Low') as LowPerformers
from (select 2007 as yr, 1 as qtr, 'Q1-2007' as qtryr union all
select 2007 as yr, 2 as qtr, 'Q2-2007' as qtryr union all
select 2007 as yr, 3 as qtr, 'Q3-2007' as qtryr union all
select 2007 as yr, 4 as qtr, 'Q4-2007' as qtryr
) driver left outer join
Table1 emp
on year(emp.start_date)*4+quarter(emp.start_date) <= driver.yr*4+qtr and
(emp.termination_date is null or
year(emp.termination_date)*4+quarter(emp.termination_date) > driver.yr*4+qtr
)
group by driver.qtryr
sqlfiddle
try this
SELECT QUARTER('2008-04-01');
http://dev.mysql.com/doc/refman/5.6/en/date-and-time-functions.html#function_quarter
and CONCAT()
Related
I'm having a hard time setting up a query(select). Database is not my specialty, so I'm turning to the experts. Let me show what I need.
----companies--- ----company_server----- -----servers---- -----print------------------------
| id | name | | company | server | | id | name | | id |page|copy | date |server
|----|-------- | |---------|----------| |----|-------- | |----|----|-----|-------------
| 1 | Company1 |1--N| 1 | 1 |N*--1| 1 | Server1 |1--N| 1 | 2 | 3 | 2020-1-11 | 1
| 2 | Company2 | | 2 | 1 | | 2 | Server2 | | 2 | 1 | 6 | 2020-1-12 | 3
| 3 | Company3 | | 3 | 2 | | 3 | Server3 | | 3 | 4 | 5 | 2020-1-13 | 4
| 3 | 3 | | 4 | Server4 | | 4 | 5 | 3 | 2020-1-15 | 2
| 5 | 3 | 4 | 2020-1-15 | 4
| 6 | 1 | 2 | 2020-1-16 | 3
| 7 | 2 | 2 | 2020-1-16 | 4
What I need?
Example where date between CAST(2020-1-12 AS DATE) AND CAST(2020-1-15 AS DATE) group by servers.id
| companies | server | sum | percent
------------------------------------------------------------------------------------
| company1,company2 | server1 | sum(page*copy) = 0 or null | 0 or NULL
| company3 | server2 | sum(page*copy) = 15 | 28.30
| company3 | server3 | sum(page*copy) = 6 | 11.32
| NULL | server4 | sum(page*copy) = 32 | 60.38
Few notes:
I need this query for MYSQL;
Every Company is linked to at least one server.
I need result grouped by server. So, every company linked to that server must be concatenated by a comma.
If the company has not yet been registered, the value null should be presented.
The sum (page * copie) must be presented as zero or null (I don't care) in the case that there was no printing in the date range.
The percentage should be calculated according to the date range entered and not with all records in the database.
The field date is stored as MYSQL DATE.
Experts, I thank you in advance for your help. I currently solve this problem with at least 03 queries to the database, but I have a conviction that I could do it with just one query.
Added a fiddle. Sorry. Im still learing how to use this.
https://www.db-fiddle.com/f/dXej7QCPe9iDopfYd1SfVh/2
Follows the query that more or less represents how far I had arrived. Notice that in the middle of the way 'server4' disappeared because there are no values for it in print in the period searched for him and I am in possession of the total of the period but I cannot calculate the percentage.
i'm stuck
select
*
from
(select
sum(p.copy * p.page) as sum1,
s.name as s_name,
s.id as s_id
from
print p
join servers s on s.id = p.server
where p.date between cast('2020-1-12' as date) and cast('2020-1-15' as date)
group by s.id) as t1
join company_server cs on cs.server = t1.s_id
right join companies c on c.id = cs.company
cross join(
select
sum(p1.copy * p1.page) sum2
from
print p1
where p1.date between cast('2020-1-12' as date) and cast('2020-1-15' as date)
) as c;
I did this query before you add fiddle, so may be name of column of mine is not same as you. Anyway, this is my solution, hope it help you.
select group_concat(c.name separator ',') as name_company,
ss.name,
sum_print as sum,
(sum_print/total) *100 as percentage
from companies c
inner join company_server cs on c.id = cs.company
right join servers ss on ss.id = cs.id
left join
(
select server,sum(page*copy) as sum_print, date from print
where date between CAST('2020-1-12' AS DATE) AND CAST('2020-1-15' AS DATE)
group by server
) tmp on tmp.server = ss.id
cross join
(select sum(page*copy) as total from print where date between CAST('2020-1-12' AS DATE) AND CAST('2020-1-15' AS DATE)) tmp2
group by id
Group and concat by comma, using GROUP_CONCAT .
You can reference this image for JOIN clause.
https://i.stack.imgur.com/6cioZ.png
In the above table I want to sum where ledgertype='Earning' and substract where
ledgertype='Deduction' and display both values..... how to write query?
Thanks in advance...
You can achieve using this. As you wanted to print earnings and deductions as well so I used sub query.
select sum_earnings , sum_deduction , sum_earnings - sum_deduction
from ( select sum(case when ledgertype = 'Earning' then ledgervalue end) sum_earrnings, sum(case when ledgertype = 'Deductions' then ledgervalue end) as sum(sum_deduction)
from ratecard ) a
I am unable to understand "Both Values" but you can get Aggregate of both types by:
Select SUM(ledgerValue), ledgerType FROM ratecard group by ledgerType
SELECT (SUM_VAL - SUBSTRACT_VAL) as balance FROM
(
select sum(ledgerValue) AS SUM_VAL FROM ratecard WHERE ledgerType ='Earning',
select sum(ledgerValue) AS SUBSTRACT_VAL FROM ratecard WHERE ledgerType = 'substract'
) t1
If you want a running total you could use a variable to calculate.
DROP TABLE IF EXISTS T;
CREATE TABLE T (ID INT,AMOUNT INT, TYP VARCHAR(10));
INSERT INTO T VALUES
(1,12500,'Earnings'),(2,3200,'Earnings'),(3,1200,'Earnings'),
(4,1200,'Deductions'),(5,200,'Deductions'),(6,600,'Deductions'),(7,500,'Deductions'),
(8,12000,'Earnings'),(9,3200,'Deductions');
select t.*,
if(t.`typ` = 'Earnings' ,#rt:=#rt+amount,#rt:=#rt-amount) RunningTotal
from t
,(select #rt:=0) rt;
order by t.id
+------+--------+------------+--------------+
| ID | AMOUNT | TYP | RunningTotal |
+------+--------+------------+--------------+
| 1 | 12500 | Earnings | 12500 |
| 2 | 3200 | Earnings | 15700 |
| 3 | 1200 | Earnings | 16900 |
| 4 | 1200 | Deductions | 15700 |
| 5 | 200 | Deductions | 15500 |
| 6 | 600 | Deductions | 14900 |
| 7 | 500 | Deductions | 14400 |
| 8 | 12000 | Earnings | 26400 |
| 9 | 3200 | Deductions | 23200 |
+------+--------+------------+--------------+
9 rows in set (0.00 sec)
Hi everybody,
I have this visitors table:
ID | Date | Purpose
1 | 20/10/2016 | Purpose1
2 | 22/10/2016 | Purpose1
3 | 25/10/2016 | Purpose2
4 | 12/11/2016 | Purpose1
5 | 14/11/2016 | Purpose2
6 | 16/11/2016 | Purpose2
Currently I'm using this query:
select case
when date like '%/10/2016' then '10/2016'
when date like '%/11/2016' then '11/2016'
end as month, count(*) as total
from visitors
where
date like '%/10/2016'
or date like '%/11/2016'
GROUP by month
I can only get month and total column count from query above. How can I achieve this output?
Month | Total | Purpose1 | Purpose2
10/2016 | 3 | 2 | 1
11/2016 | 3 | 1 | 2
Thanks!
Consider the following...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,Date DATE NOT NULL
,Purpose VARCHAR(12) NOT NULL
);
INSERT INTO my_table VALUES
(1,'2016-10-20','Purpose1'),
(2,'2016-10-22','Purpose1'),
(3,'2016-10-25','Purpose2'),
(4,'2016-11-12','Purpose1'),
(5,'2016-11-14','Purpose2'),
(6,'2016-11-16','Purpose2');
SELECT DATE_FORMAT(date,'%Y-%m') month
, SUM(purpose = 'purpose1') purpose1
, SUM(purpose = 'purpose2') purpose2
, COUNT(*) total
FROM my_table
GROUP
BY month;
+---------+----------+----------+-------+
| month | purpose1 | purpose2 | total |
+---------+----------+----------+-------+
| 2016-10 | 2 | 1 | 3 |
| 2016-11 | 1 | 2 | 3 |
+---------+----------+----------+-------+
..or (and in my view, better, provided you have access to application code)...
SELECT DATE_FORMAT(date,'%Y-%m') month
, purpose
, COUNT(*) total
FROM my_table
GROUP
BY month
, purpose;
+---------+----------+-------+
| month | purpose | total |
+---------+----------+-------+
| 2016-10 | Purpose1 | 2 |
| 2016-10 | Purpose2 | 1 |
| 2016-11 | Purpose1 | 1 |
| 2016-11 | Purpose2 | 2 |
+---------+----------+-------+
Transposing tables isn't very fast. It is better to do so in some small program.
If you do a
select case
when date like '%/10/2016' then '10/2016'
when date like '%/11/2016' then '11/2016'
end as month, count(*) as total, Purpose
from visitors
where
date like '%/10/2016'
or date like '%/11/2016'
GROUP by month, Purpose
You'll have a good starting point.
You might need to add an ORDER BY clause (depending on your DBMS).
If (and only if) you only have two purposes in your table and the table isn't huge in size, you can create two views and join them.
I have a Mysql table with the following data.
|ID | Date | BillNumber|BillMonth | Amount | Name |AccNum |
| 2 |2015-09-25| 454345 | 092015 | 135.00 |Andrew Good| 735976|
| 3 |2015-09-26| 356282 | 092015 | 142.00 |Peter Pan | 123489|
| 4 |2015-08-11| 312738 | 082015 | 162.00 |Andrew Good| 735976|
| 5 |2015-07-12| 287628 | 072015 | 220.67 |Andrew Good| 735976|
| 6 |2015-06-12| 100756 | 062015 | 556.34 |Andrew Good| 735976|
What I wanted to achieve is to retrieve the data of Andrew Good with AccNum 735976 for the BillMonth of 092015, provided that the user can entry any of his BillNumber(past/current).
If the reason that that row is of interest is because it is the latest of his rows, try:
select *
from tbl t
where name = ( select name
from tbl
where billnumber = 100756 -- can be any of his
)
and date = ( select max(date)
from tbl x
where x.name = t.name
)
(the billnumber can be any of his)
Using table below, How would get a column for 5 period moving average, 10 period moving average, 5 period exponential moving average.
+--------+------------+
| price | data_date |
+--------+------------+
| 122.29 | 2009-10-08 |
| 122.78 | 2009-10-07 |
| 121.35 | 2009-10-06 |
| 119.75 | 2009-10-05 |
| 119.02 | 2009-10-02 |
| 117.90 | 2009-10-01 |
| 119.61 | 2009-09-30 |
| 118.81 | 2009-09-29 |
| 119.33 | 2009-09-28 |
| 121.08 | 2009-09-25 |
+--------+------------+
The 5-row moving average in your example won't work. The LIMIT operator applies to the return set, not the rows being considered for the aggregates, so changing it makes no difference to the aggregate values.
SELECT AVG(a.price) FROM (SELECT price FROM t1 WHERE data_date <= ? ORDER BY data_date DESC LIMIT 5) AS a;
Replace ? with the date whose MA you need.
SELECT t1.data_date,
( SELECT SUM(t2.price) / COUNT(t2.price) as MA5 FROM mytable AS t2 WHERE DATEDIFF(t1.data_date, t2.data_date) BETWEEN 0 AND 6 )
FROM mytable AS t1 ORDER BY t1.data_date;
Change 6 to 13 for 10-day MA