Maintain Revision History in MySQL Database - mysql

I am learning how PHP/jQuery/MySQL work with each other by creating a web app that maintains a record of my bills and payment made.
I can't wrap my head around on how to structure my database so that I can keep track of payments made. Kinda like a payment history.
I would like to maintain a history of payment amount and the date the payment was made.
Here is my current 'Bills' table.
+----+-------------+-------------+-----------------+----------+
| id | creditor | amount_owed | monthly_payment | due_date |
+----+-------------+-------------+-----------------+----------+
| 42 | Capital One | 500.00 | 55.00 | 21 |
| 43 | sdf | 33.00 | 33.00 | 30 |
| 44 | Car Loan | 15000.00 | 300.00 | 14 |
+----+-------------+-------------+-----------------+----------+
I was thinking about adding a couple of columns (payment amount/payment date) and duplicating the ids... Anybody of any suggestions?
Thanks!

I would create a new table bills_payments with an FK to the bills table. That way you can keep track of each paymant made for every bill registry. And plus, you can put interest fees/charges on this table to. It will be like:
Bills
+----+-------------+-------------+-----------------+----------+
| id | creditor | amount_owed | monthly_payment | due_date |
+----+-------------+-------------+-----------------+----------+
| 42 | Capital One | 500.00 | 55.00 | 21 |
| 43 | sdf | 33.00 | 33.00 | 30 |
| 44 | Car Loan | 15000.00 | 300.00 | 14 |
+----+-------------+-------------+-----------------+----------+
Bills_payments
+----+-------------+-------------+-----------------+---------------+
| idBill | paydValue | date | InterestFee | due_date_limit|
+--------+------------------------+----------------+---------------+
| 42 | 55.00 | 2013-11-21 | | 2013-11-21 |
| 43 | 45.00 | 2013-12-05 | 12.00 | 2013-11-30 |
| 44 | 300.00 | 2013-12-14 | 300.00 | 2013-12-14 |
+----+-------------+-------------+-----------------+---------------+
The due date limit you will have to calculate since you just put the due date on the main table.

Related

difference between dates excluding custom periods

Good morning,
I need a solution for counting days between specific dates. In addition I need to exclude specific dates (public holidays and weekends), which is easy and there are plenty of instructions on how to do it.
But I need to accomplish one more thing. For every person, I also have custom vacation periods and I need them to be subtracted from the previous result.
At the moment, i have two tables. One for the custom vacation periods:
+-----+----------+---------------------+---------------------+------+
| id | employee | start | end | away |
+-----+----------+---------------------+---------------------+------+
| 835 | 2.3 | 2016-12-05 00:00:00 | 2016-12-10 00:00:00 | P |
| 836 | 5.3.5.1 | 2017-01-03 00:00:00 | 2017-01-23 00:00:00 | P |
| 837 | 5.3.5.6 | 2016-12-21 00:00:00 | 2017-04-01 00:00:00 | P |
| 838 | 5.3.3.1 | 2017-01-01 00:00:00 | 2017-01-03 00:00:00 | P |
| 839 | 5.3.1.2 | 2017-01-03 00:00:00 | 2017-01-12 00:00:00 | P |
| 840 | 5.3.1.6 | 2017-01-01 00:00:00 | 2017-01-01 00:00:00 | P |
| 841 | 5.1.7 | 2017-01-09 00:00:00 | 2017-01-15 00:00:00 | P |
| 842 | 2.2 | 2017-02-16 00:00:00 | 2017-02-26 00:00:00 | P |
| 843 | 2.5 | 2017-07-31 00:00:00 | 2017-08-06 00:00:00 | P |
| 844 | 2.5 | 2017-08-21 00:00:00 | 2017-08-27 00:00:00 | P |
| 845 | 2.5 | 2017-06-26 00:00:00 | 2017-07-09 00:00:00 | P |
| 846 | 2.4 | 2017-04-04 00:00:00 | 2017-04-08 00:00:00 | P |
+-----+----------+---------------------+---------------------+------+
12 rows in set (0.00 sec)
The reason I have date and time on start and end is that the table actually has info about their working schedule also. The vacation schedule is marked by column 'away' set as 'P'.
The second table looks like this:
+-----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| date | varchar(45) | YES | | NULL | |
| dayofweek | varchar(45) | YES | | NULL | |
| short | varchar(45) | YES | | NULL | |
| holiday | varchar(45) | YES | | NULL | |
+-----------+-------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
This table is basically a calendar with additional information about what day of week it is (i know that this can be done with dayofweek() but i need this column also), 'short' determines whether it's a shortened workday (essential when calculating hours because there are a couple of days in a year when the working day is shorter) and 'holiday' which marks public holidays.
I am trying to figure out how to calculate working days during one month (01.08.2017 - 31.08.2017) by subtracting public holidays and weekends (which I can do and is relatively easy) and also subtract custom period of vacations. The main problem is that for some people, there can be more than one period of absence during one month.
If you look at the example above, employee 2.5 has a vacation period that starts in July and ends in August and I need to subtract only the amount in that period that is in August. Employee 2.5 has another vacation in August and I need to subtract this also. In addition to that, this employee has another vacation from June to July.
The perfect outcome would be something like this:
+----------+-------+---------------+--------------+---------------+
| employee | month | working hours | working days | vacation days |
+----------+-------+---------------+--------------+---------------+
The only solution I am able to come up with is to create a new table called vacations with a column for each day and each row shows data for one employee. Or the other way around where employees are columns and rows are dates. But I would not like to start playing with this idea before i know that there isn't an easier way to do it.
Once again, I am sure that there is an easy function in mysql for this but I fail to figure it out.
To calculate working hours do this:
$to_time = strtotime("$row[2]");
$from_time = strtotime("$row[3]");
$diff = $to_time - $from_time
echo round(abs($diff) / 3600,2). " hour(s)";
Where $row[2] & $rows[3] are your start and end dates. They /3600 is for calculating hours, you can get minutes by just writing 60 instead of 3600.
As for the working days and vacations, you can set up a counter and increment it for days and decrement it for vacations using the $diff variable. Count the number of hours or days you like and then increment/decrement it the way you like.
I tidied it up a bit. I finally got what I needed.
At first I changed the calendar table:
mysql> select id,date,workday from calendar where date between '2017-06-20' and '2017-06-30';
+-----+------------+---------+
| id | date | workday |
+-----+------------+---------+
| 202 | 2017-06-20 | 1 |
| 203 | 2017-06-21 | 1 |
| 204 | 2017-06-22 | 0.625 |
| 205 | 2017-06-23 | Holiday |
| 206 | 2017-06-24 | Holiday |
| 207 | 2017-06-25 | NULL |
| 208 | 2017-06-26 | 1 |
| 209 | 2017-06-27 | 1 |
| 210 | 2017-06-28 | 1 |
| 211 | 2017-06-29 | 1 |
| 212 | 2017-06-30 | 1 |
+-----+------------+---------+
11 rows in set (0.00 sec)
1 in workday column says it's an ordinary workday, NULL means that it is not (weekend) and 0.625 is shortened workday (5/8=0,625).a shortened working day is 5 hours. This basically means if i sum the workday column and multiply it with the length of an ordinary workday, I get the normal working hours according to the law between selected period of time.
To do this, at the moment i just set up some variables, this is just a work in progress:
set #START='2016-12-01';
set #END='2016-12-31';
set #WORKDAY=8;
set #norm=(select sum(workday)*#workday from calendar where date between #start and #end);
So the variables #START and #END give me the period i am interested in. #NORM will give me the normal working hours if one is not on vacation or sick leave between #START and #END.
I added some generic data to schedule:
mysql> select id,position,start,end,away from schedule where away='P';
+-----+----------+---------------------+---------------------+------+
| id | position | start | end | away |
+-----+----------+---------------------+---------------------+------+
| 835 | 2.3 | 2016-12-05 00:00:00 | 2016-12-10 00:00:00 | P |
| 836 | 5.3.5.1 | 2017-01-03 00:00:00 | 2017-01-23 00:00:00 | P |
| 837 | 5.3.5.6 | 2016-12-21 00:00:00 | 2017-04-01 00:00:00 | P |
| 838 | 5.3.3.1 | 2017-01-01 00:00:00 | 2017-01-03 00:00:00 | P |
| 839 | 5.3.1.2 | 2017-01-03 00:00:00 | 2017-01-12 00:00:00 | P |
| 840 | 5.3.1.6 | 2017-01-01 00:00:00 | 2017-01-01 00:00:00 | P |
| 841 | 5.1.7 | 2017-01-09 00:00:00 | 2017-01-15 00:00:00 | P |
| 842 | 2.2 | 2017-02-16 00:00:00 | 2017-02-26 00:00:00 | P |
| 843 | 2.5 | 2017-07-31 00:00:00 | 2017-08-06 00:00:00 | P |
| 844 | 2.5 | 2017-08-21 00:00:00 | 2017-08-27 00:00:00 | P |
| 845 | 2.5 | 2017-06-26 00:00:00 | 2017-07-09 00:00:00 | P |
| 846 | 2.4 | 2017-04-04 00:00:00 | 2017-04-08 00:00:00 | P |
| 847 | 2.3 | 2017-07-31 00:00:00 | 2017-08-06 00:00:00 | P |
| 848 | 2.3 | 2017-08-21 00:00:00 | 2017-08-27 00:00:00 | P |
| 849 | 2.3 | 2017-06-26 00:00:00 | 2017-07-09 00:00:00 | P |
| 850 | 2.5 | 2017-08-29 00:00:00 | 2017-09-15 00:00:00 | P |
| 851 | 2.3 | 2017-08-29 00:00:00 | 2017-09-15 00:00:00 | P |
| 852 | 2.1 | 2016-11-15 00:00:00 | 2016-12-20 00:00:00 | P |
| 853 | 2.2 | 2016-11-10 00:00:00 | 2017-01-15 00:00:00 | P |
+-----+----------+---------------------+---------------------+------+
19 rows in set (0.00 sec)
And to get the info about each employees specific working I use following select:
SELECT position,#NORM AS normhrs,#NORM - (SUM(vac_workday))*#WORKDAY AS wrkhrs
FROM
(
SELECT position,holiday_start,holiday_end,
(SELECT SUM(workday) FROM calendar WHERE date BETWEEN holiday_start AND holiday_end) AS vac_workday
FROM
(
SELECT position,
DATE_FORMAT(CASE WHEN start<=#START THEN #START ELSE start END,'%Y-%m-%d') AS 'holiday_start',
DATE_FORMAT(CASE WHEN end>=#END THEN #END ELSE end END,'%Y-%m-%d') AS 'holiday_end'
FROM schedule WHERE away IS NOT NULL AND DATE_FORMAT(CASE WHEN start<=#START AND end>=#START THEN #START
WHEN start>=#START AND start<=#END THEN start
ELSE NULL end,'%Y-%m')=DATE_FORMAT(#START,'%Y-%m')
)
AS outertable
)
AS outertable2 GROUP BY position;
which gives me the output. there are only people who have vacations from #START to #END. If the person is not in the output, norm hours apply:
+----------+---------+--------+
| position | normhrs | wrkhrs |
+----------+---------+--------+
| 2.1 | 165 | 53 |
| 2.2 | 165 | 0 |
| 2.3 | 165 | 133 |
| 5.3.5.6 | 165 | 120 |
+----------+---------+--------+
4 rows in set, 6 warnings (0.00 sec)
This is the output i was looking for. i still need to come up with SELECT to sum up the actual working hours but it is easy enough not to put it in here.
Sorry, i know i'm over explaining some stuff but i being total noob, have found similar, rather superthorough answers, very helpful.

Select to Calculate Sales Average by Customer taking First Sales into Account MYSQL

I have this Sales Table by Customer in Mysql
+-----------+------------+-------+-----------------+
| Customer | Date | Sales | Date_First_Sale |
+-----------+------------+-------+-----------------+
| Jane | 2016-04-30 | 903 | 2015-02-03 |
| Jane | 2016-02-03 | 51 | 2015-02-03 |
| Jane | 2016-03-09 | 192 | 2015-02-03 |
| John | 2016-05-10 | 64 | 2015-10-03 |
| John | 2016-04-16 | 880 | 2015-10-03 |
| John | 2016-08-17 | 386 | 2015-10-03 |
| John | 2016-03-01 | 503 | 2015-10-03 |
| Juan | 2016-07-06 | 765 | 2015-09-01 |
| Juan | 2016-01-20 | 36 | 2015-09-01 |
| Juan | 2016-03-03 | 928 | 2015-09-01 |
| Momo | 2016-06-29 | 573 | 2015-09-01 |
| Momo | 2016-04-25 | 375 | 2015-09-01 |
| Momo | 2016-06-10 | 999 | 2015-09-01 |
| Nour | 2016-02-28 | 956 | 2015-05-01 |
| Nour | 2016-01-03 | 582 | 2015-05-01 |
| Nour | 2016-08-17 | 366 | 2015-05-01 |
| Philip | 2016-03-22 | 296 | 2015-09-01 |
| Philip | 2016-04-14 | 459 | 2015-09-01 |
| Sylvie | 2016-03-29 | 551 | 2015-09-03 |
| Sylvie | 2016-02-14 | 896 | 2015-09-03 |
+-----------+------------+-------+-----------------+
I need to calculate the Average Sales by Customer calculated on a WEEKLY basis in the last 12 months (52 or 53 weeks depending on the calendar?), starting from Today.
Now the problem is that I do not want to calculate the Average Weekly sales by customer for customers that have made their first purchase in a range below 12 months, for instance If current date is 2016-09-01, and Customers made his first purchase on 2016-07-24, the average should not be calculated on a 12 months basis but on the weekly sales generated between the 2016-07-24 and the 2016-09-01 only.
For customers who have made their First purchase before the 12 months range, then the average should be calculated on 12 months only.
I have been trying to find this SELECT but have not reached anything due to my limited Mysql knowledge for more complex queries!
Thanks in advance for your help
This should help you
SELECT Customer, (total_sales/weeks) AS avg_sales FROM
(
SELECT Customer, total_sales, Date_First_Sale, IF(weeks>52,52,weeks) as weeks
FROM (
SELECT Customer, SUM(Sales) AS total_sales, Date_First_Sale, TIMESTAMPDIFF(WEEK, Date_First_Sale, CURDATE()) AS weeks
FROM (
SELECT Customer, sales , Date_First_Sale
FROM test.SO_customer
WHERE Date > DATE_SUB(curdate(), INTERVAL 1 YEAR)
) as subTable
GROUP BY Customer
) as subTable2
) as subTable3

Magento Join two tables

I am new in magento.
I am creating a custom megento report. I decide to join two tables rev_table and emp_table.
emp_id | datefield | emp_name | salary |cpf | other_benefits
1 | 2013-11-12 00:00:00 | abc | 18000 | 2000 | 3000
2 | 2013-11-20 00:00:00 | test1 | 20000 | 1000 | 1000
3 | 2013-11-21 00:00:00 | test | 18000 | 2000 | 2000
4 | 2013-12-11 00:00:00 | demo | 15000 | 3000 | 2000
5 | 2013-12-20 00:00:00 | ash | 8000 | 5000 | 3000
6 | 2013-12-24 00:00:00 | test1 | 18000 | 1000 | 500
revenue_id | datefield | revenue | rental | repair | recruitment |wages
1 | 2013-12-24 07:02:00 | 200 | 22 | 23 | 546 |
2 | 2013-11-19 01:01:00 | 456 | 56 | 56 | 565 |
3 | 2013-10-09 00:00:00 | 500 | 565 | 564 | 56 |
4 | 2013-11-13 00:00:00 | 900 | 435 | 345 | 5 |
i want to show total of employee table of 1 month into rev_table report in magento. for example employes total wages of november month is (67000). this will show as a new column in revenue report of november month.
then result should be
revenue_id | datefield | revenue | rental | repair | recruitment | wages <br/>
2 | 2013-11-19 01:01:00 | 456 | 56 | 56 | 565 | 67000 <br/>
4 | 2013-11-13 00:00:00 | 900 | 435 | 345 | 5 |
please help me to explain me how to add joins in magento collections and add coloume in report grid.
Thanks

SQL server pivot table for time keeping

I have a time keeping table that records the following data:
+----------------+-------------------------+-------+
| TK_EMPLOYEE_ID | TK_DATETIME | TK_ID |
+----------------+-------------------------+-------+
| 101 | 2013-09-30 08:01:54.000 | 1 |
| 101 | 2013-09-30 12:02:16.000 | 2 |
| 101 | 2013-09-30 12:30:12.000 | 3 |
| 101 | 2013-09-30 16:31:02.000 | 4 |
| 101 | 2013-10-01 08:33:59.000 | 5 |
| 101 | 2013-10-01 12:05:59.000 | 6 |
| 101 | 2013-10-01 12:30:29.000 | 7 |
| 101 | 2013-10-01 16:40:48.000 | 8 |
| 102 | 2013-10-01 08:00:48.000 | 9 |
| 102 | 2013-10-01 12:00:48.000 | 10|
+----------------+-------------------------+-------+
The clock entries are taken so that the odd scans are "CLOCK IN" and the even are "CLOCK OUT". So in the table above we can see that the employee clocked in at 8:01am, clocked out at 12:02; clocked back in from lunch at 12:30 and left work and 16:31.
How could I format display this in a SQL pivot table to display something like the following detailing entries for each day of the week?
EMPID | Mon | Tue | Wed
101 | 8:01 - 12:02 (4:01) | 08:33 - 12:05 (03:32) | etc
| 12:30- 16:31 (4:01) | 12:30 - 16:40 (04:10 |
102 | 8:00- 12:00 (4:00)
The time difference between the two times is shown in brackets.
I plan on using SSRS to display the results.

Complex MySQL query summing joined records where parent and child ids are equal

Maybe this will be an easy one for some of you MySQL masters who see this stuff like a level 3 children's book.
I have multiple tables that I'm joining to produce statistical data for a report and I'm getting tripped up at the moment trying to figure it out. It's obviously imperative the figures are correct because it impacts a number of decisions going forward.
Here's the lay of the land (not the full picture, but you'll get the point):
Affiliate Table
+----+-----------+------------+---------------------+
| id | firstname | lastname | created_date |
+----+-----------+------------+---------------------+
| 1 | Mike | Johnson | 2010-11-22 17:44:37 |
| 2 | Trevor | Wilson | 2010-12-23 16:24:24 |
| 3 | Bob | Parker | 2011-11-04 10:33:49 |
+----+-----------+------------+---------------------+
Now our query should only find results for Bob Parker (id 3) so I'll only show example results for Bob.
Affiliate Link Table
+-----+-----------+--------------+-----------+----------+---------------------+
| id | parent_id | affiliate_id | link_type | linkhash | created_date |
+-----+-----------+--------------+-----------+----------+---------------------+
| 21 | NULL | 3 | PRODUCT | fa2e82a7 | 2011-06-15 16:18:37 |
| 27 | NULL | 3 | PRODUCT | 55de2ae7 | 2011-06-23 01:03:00 |
| 28 | NULL | 3 | PRODUCT | 02cae72f | 2011-06-23 01:03:00 |
| 29 | 27 | 3 | PRODUCT | a4dfb2c8 | 2011-06-23 01:03:00 |
| 30 | 28 | 3 | PRODUCT | 72cea1b2 | 2011-06-23 01:03:00 |
| 36 | 21 | 3 | PRODUCT | fa2e82a7 | 2011-06-23 01:07:03 |
| 59 | 21 | 3 | PRODUCT | ec33413f | 2011-11-04 17:49:17 |
| 60 | 27 | 3 | PRODUCT | f701188c | 2011-11-04 17:49:17 |
| 69 | 21 | 3 | PRODUCT | 6dfb89fd | 2011-11-04 17:49:17 |
+-----+-----------+--------------+-----------+----------+---------------------+
Affiliate Stats
+--------+--------------+--------------------+----------+---------------------+
| id | affiliate_id | link_id | order_id | type | created_date |
+--------+--------------+---------+----------+----------+---------------------+
| 86570 | 3 | 21 | NULL | CLICK | 2013-01-01 00:07:31 |
| 86574 | 3 | 21 | NULL | PAGEVIEW | 2013-01-01 00:08:53 |
| 86579 | 3 | 21 | 411 | SALE | 2013-01-01 00:09:52 |
| 86580 | 3 | 36 | NULL | CLICK | 2013-01-01 00:09:55 |
| 86582 | 3 | 36 | NULL | PAGEVIEW | 2013-01-01 00:09:56 |
| 86583 | 3 | 28 | NULL | CLICK | 2013-01-01 00:11:04 |
| 86584 | 3 | 28 | NULL | PAGEVIEW | 2013-01-01 00:11:04 |
| 86586 | 3 | 30 | NULL | CLICK | 2013-01-01 00:30:18 |
| 86587 | 3 | 30 | NULL | PAGEVIEW | 2013-01-01 00:30:20 |
| 86611 | 3 | 69 | NULL | CLICK | 2013-01-01 00:40:19 |
| 86613 | 3 | 69 | NULL | PAGEVIEW | 2013-01-01 00:40:19 |
| 86619 | 3 | 69 | 413 | SALE | 2013-01-01 00:42:12 |
| 86622 | 3 | 60 | NULL | CLICK | 2013-01-01 00:46:00 |
| 86624 | 3 | 60 | NULL | PAGEVIEW | 2013-01-01 00:46:01 |
| 86641 | 3 | 60 | NULL | PAGEVIEW | 2013-01-01 00:55:58 |
| 86642 | 3 | 30 | 415 | SALE | 2013-01-01 00:56:35 |
| 86643 | 3 | 28 | NULL | PAGEVIEW | 2013-01-01 00:56:43 |
| 86644 | 3 | 60 | 417 | SALE | 2013-01-01 00:56:52 |
+--------+--------------+---------+----------+----------+---------------------+
Orders
+------+--------------+---------+---------------------+
| id | affiliate_id | total | created_date |
+------+--------------+---------+---------------------+
| 411 | 3 | 138.62 | 2013-01-01 00:09:50 |
| 413 | 3 | 312.87 | 2013-01-01 00:09:52 |
| 415 | 3 | 242.59 | 2013-01-01 00:09:55 |
| 417 | 3 | 171.18 | 2013-01-01 00:09:55 |
+------+--------------+---------+---------------------+
Now the results that I need should look like this (only show main/parent link id)
+---------+---------+
| link_id | total |
+---------+---------+
| 21 | 451.49 | <- 1 order from parent (21), 1 from child (69)
| 27 | 171.18 | <- 1 order from child (69)
| 28 | 242.59 | <- 1 order from child (30)
+---------+---------+
I'm not quite sure how to write the query so that I can sum where affiliate_link.id and affiliate_link.parent_id are combined. Is this even possible with a couple of JOINs and GROUPing?
I'm not too sure why you have denormalised affiliate_id (by placing it in each table) and, therefore, whether one can rely on all Stats and Orders that stem from a particular Link to have the same affiliate_id as that Link.
If it's possible, I'd suggest changing the AffiliateLink.parent_id column such that parent records point to themselves (rather than NULL):
UPDATE AffiliateLink SET parent_id = id WHERE parent_id IS NULL
Then it's a simple case of joining and grouping:
SELECT AffiliateLink.parent_id AS link_id,
SUM(Orders.total) AS total
FROM AffiliateLink
JOIN AffiliateStats ON AffiliateStats.link_id = AffiliateLink.id
JOIN Orders ON Orders.id = AffiliateStats.order_id
WHERE AffiliateLink.affiliate_id = 3
GROUP BY AffiliateLink.parent_id
See it on sqlfiddle.
If it's not possible to make the change, you can effectively create the resulting AffiliateLink table using UNION (but beware the performance implications, as MySQL will not be able to use indexes on the result):
(
SELECT parent_id, id, affiliate_id FROM AffiliateLink WHERE parent_id IS NOT NULL
UNION ALL
SELECT id , id, affiliate_id FROM AffiliateLink WHERE parent_id IS NULL
) AS AffiliateLink
See it on sqlfiddle.