PHP / MySQL: synchronize two fields in the same table - php

I need to synchronize two different booking calendars, beacause both calendars book the same room (or the same event).
So, if a client book a day (and hours) in calendar_01, this value (booked day and hours) will be automatically updated in calendars_02 (and vice versa).
It's important to update (and rewrite the new value) in order of the last time (most recent booking) without a continuous loop.
MySql DB
I'm using a plugin for this and in "calendars" database there is a table called "days", in this table I can see this:
+--------------+-------------+------------+------+----------------------------------------------------------+
| unique_key | calendar_id | day | year | data |
+--------------+-------------+------------+------+----------------------------------------------------------+
| 1_2014-08-20 | 1 | 2014-08-20 | 2014 | available h10-12; booked h12-14; in pending h14-16; |
| 2_2014-08-20 | 2 | 2014-08-20 | 2014 | available h 10 - 12; available h12-14; available h14-16; |
| 1_2014-08-21 | 1 | 2014-08-21 | 2014 | available h10-12; available-14; available h14-16; |
| 2_2014-08-21 | 2 | 2014-08-21 | 2014 | booked h10-12; booked h12-14; in pending h14-16; |
+--------------+-------------+------------+------+----------------------------------------------------------+
Simplification: column "data" contains the values (TEXT type) that record every rebooking, so:
+--------------+-------------+------------+------+--------------+
| unique_key | calendar_id | day | year | data |
+--------------+-------------+------------+------+--------------+
| 1_2014-08-20 | 1 | 2014-08-20 | 2014 | text value A |
| 2_2014-08-20 | 2 | 2014-08-20 | 2014 | text value B |
| 1_2014-08-21 | 1 | 2014-08-21 | 2014 | text value C |
| 2_2014-08-21 | 2 | 2014-08-21 | 2014 | text value D |
+--------------+-------------+------------+------+--------------+
I need to update the values of the same column "data", like this:
+--------------+-------------+------------+------+--------------+
| unique_key | calendar_id | day | year | data |
+--------------+-------------+------------+------+--------------+
| 1_2014-08-20 | 1 | 2014-08-20 | 2014 | text value A |
| 2_2014-08-20 | 2 | 2014-08-20 | 2014 | text value A |
| 1_2014-08-21 | 1 | 2014-08-21 | 2014 | text value D |
| 2_2014-08-21 | 2 | 2014-08-21 | 2014 | text value D |
| 1_2014-08-22 | 1 | 2014-08-22 | 2014 | text value X |
| 2_2014-08-22 | 2 | 2014-08-22 | 2014 | text value X |
| 1_2014-08-23 | 1 | 2014-08-23 | 2014 | text value Y |
| 2_2014-08-23 | 2 | 2014-08-23 | 2014 | text value Y |
+--------------+-------------+------------+------+--------------+
Many thanks in advance for any help!

I would strongly advice against syncing/Data Replication. You'd need to run a deamon 24/7, the risk of running into issues is much higher, it's also less eficient since It has to keep checking for new data in both tables which also means a delay for people to see their new bookings on the site. And it not so easy to debug when something does go wrong with the deamon.
The following solution is much easier to debug, more efficient. I would suggest you write abstract CRUD code for the data: Create, Read, Update and Delete. Create and Update are probably the ones you're most interested in, what you would do is something like this:
<?php
function create($id, $data)
{
$id = mysql_real_escape_string($id);
$data = mysql_real_escape_string($data['data']);
mysqL_query("INSERT INTO calendars (unique_key,data) VALUES('".$id."','".$data."')");
mysqL_query("INSERT INTO days (unique_key,data) VALUES('".$id."','".$data."')");
}
function update($id, $data)
{
$id = mysql_real_escape_string($id);
$data = mysql_real_escape_string($data['data']);
mysqL_query("UPDATE calendars SET data = '".$data."' WHERE unique_key = '".$id."'");
mysqL_query("UPDATE days SET data = '".$data."' WHERE unique_key = '".$id."'");
}
create('1_2014-08-20', array(
'data' => 'data here'
));
update('1_2014-08-20', array(
'data' => 'data here'
));
This is as simple as passing data into it. If you ever modify the SQL structure you can create a new abstraction set of functions/classes that follows the new database structure and it's as easy as swapping out an include.

Related

Dynamically create MySQL table columns

I have the following MySQL table which is structured like that:
| id | bonus0 |
Now I want to add the following data set:
| id | bonus0 | bonus1 | bonus2 | bonus3 |
| 10 | 4582 | 2552 | 8945 | 7564 |
As you can see the columns bonus1 - bonus3 arenĀ“t created yet.
How would a php script/ query look like which checks if enough columns are already available and if not which will create the missing ones with consecutive numbers at the end of the word "bonus"?
So in the example the columns bonus1 - bonus3 would be created automatically by the script.
In reality (I mean a normalized relational database) you should have 3 tables. Lets call them people, bonuses and bonus_to_person
people looks like:
+-----------------+------------+
| person_id | name |
+_________________+____________+
| 1 | john |
+-----------------+------------+
| 2 | frank |
+-----------------+------------+
bonuses Looks like
+----------------+--------------+
| bonus_id | amount |
+________________+______________+
| 1 | 1000 |
+----------------+--------------+
| 2 | 1150 |
+----------------+--------------+
| 3 | 1200 |
+----------------+--------------+
| 4 | 900 |
+----------------+--------------+
| 5 | 150 |
+----------------+--------------+
| 6 | 200 |
+----------------+--------------+
bonus_to_person Looks like
+----------------+-----------------+
| bonus_id | person_id |
+________________+_________________+
| 1 | 1 |
+----------------+-----------------+
| 2 | 2 |
+----------------+-----------------+
| 3 | 2 |
+----------------+-----------------+
| 4 | 1 |
+----------------+-----------------+
| 5 | 1 |
+----------------+-----------------+
| 6 | 1 |
+----------------+-----------------+
This way, any ONE person can have unlimited bonuses simply by INSERTING into bonuses with the amount, and INSERTING into bonus_to_person with the bonus_id and person_id
The retrieval of this data would look like
SELECT a.name, c.amount from people a
LEFT JOIN bonus_to_people b
ON a.person_id = b.person_id
LEFT JOIN bonuses c
ON c.bonus_id = b.bonus_id
WHERE a.person.id = 1;
Your result from something like this would look like
+------------+----+-------+
| name | amount |
+____________+____________+
| john | 1000 |
+------------+------------+
| john | 900 |
+------------+------------+
| john | 150 |
+------------+------------+
| john | 200 |
+------------+------------+
You should be using this normalized approach for any database that will continue growing -- Growing "deeper" than "wider" is better in your case ..
// Get existing columns of the table
// $queryResult = run SQL query using PDO/mysqli/your favorite thing: SHOW COLUMNS FROM `table`
// Specify wanted columns
$search = ['bonus0', 'bonus1', 'bonus2', 'bonus3'];
// Get just the field names from the resultset
$fields = array_column($queryResult, 'Field');
// Find what's missing
$missing = array_diff($search, $fields);
// Add missing columns to the table
foreach ($missing as $field) {
// Run SQL query: ALTER TABLE `table` ADD COLUMN $field INT
}

How to show data based on date with column loop in one month in PHP MYSQL?

First, I have query like this:
SELECT
a.idpeg,
a.tanggal,
a.jam_masuk,
a.jam_pulang,
a.mode_absen
FROM
`tp_rekap_2018-01` a
WHERE
id_opd = '3'
AND periode = '2018-01'
And the result is:
+------+------------+-----------+------------+-----------+
|idpeg | tanggal | jam_masuk | jam_pulang | mode_absen|
+------+------------+-----------+------------+-----------+
|001 | 2018-01-01 | 07:01:01 | 14:01:01 | 1 |
|001 | 2018-01-02 | 08:01:01 | 15:01:01 | 1 |
|001 | 2018-01-03 | 09:01:01 | NULL | 1 |
|002 | 2018-01-01 | 10:01:01 | 16:01:01 | 1 |
|003 | 2018-01-01 | 11:01:01 | 17:01:01 | 1 |
|003 | 2018-01-02 | 12:01:01 | 18:01:01 | 1 |
+------+------------+-----------+------------+-----------+
my question is what I have to do when I want to show result of query with this format of table
Friend of mine suggest me to use the 'for' to loop the date/day and I was successfully generate day from day 1 to the last day of the month. But I can't get the loop script of date/day based on 'idpeg' from the left.
thx b4.
The correct way, i think is using PIVOTS. https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx
There are many ways to do it. I can tell you what will be good solution in my opinion.
First of all, looks like you need some user system (make some user object in your PHP script and file or record in the database representing the user).
Then add the date records respectively to user id:
for (i = 0; i < idpeg.size; ++i)
user[a.idpeg[i]] = a.tanggal[i]
Then just use loop to print user data in columns as you did before.

Use file_get_contents in PHP Array to Update MySQL

I have a database contains ID and name of my Staff (DATABASE 1):
--------------
| ID | name |
--------------
| 1 | Mr.AA |
| 2 | Mr.AB |
|... | ... |
| 78 | Mr.CZ |
--------------
Then my colleague has the staff absence database per day for 2 years (DATABASE 2):
Tablename: Table_for_Mr.AA
--------------------------
| ID | date | work |
--------------------------
| 1 | 2016-01-01 | Yes |
| 2 | 2016-01-02 | Yes |
| 3 | 2016-01-03 | No |
|... | ... | ... |
|730 | 2017-12-31 | Yes |
--------------------------
Due to our agreement, we hold each database ourselves (2 parties), so each database is stored in different server.
Lately I need to get the data from DATABASE 2 to be shown in my website and I can ask my colleague to make PHP file that return the array for each name (www.colleaguewebsite/staff/absence.php?name=Mr.AA).
I already made the new 'workstat' database (DATABASE 3) in my server with this detail:
---------------------------------
| ID | date | Name | work |
---------------------------------
| 1 | 2016-01-01 |
| 2 | 2016-01-02 |
| 3 | 2016-01-03 |
|... | ... |
---------------------------------
this is the best I can do:
$sourceURL = 'www.colleaguewebsite/staff/absence.php'
$sql1= $conn->query("select * FROM staff ");
while($row_1 = $sql1->fetch_array()){
$name= $row_1 ['name'];
//getting the absence detail from each staff
$json_1 = file_get_contents($sourceURL.'?name='.$name);
$data_1 = json_decode($json_1,true);
foreach($data_1 as $value_1){
$date = $value_1['date'];
$work = $value_1['work'];
//if the correspondence date is exist then update, otherwise add
$sql_2 = $conn->query("select * FROM workstat WHERE date='$date' AND name='$name");
if ($sql_2->num_rows > 0){
$update=$conn->query("UPDATE workstat set name='$name', work='$work' WHERE date='$date' ");
}else{
$addnew=$ob->query("INSERT INTO availability (date, name, work) VALUES ('$date', '$name', '$work'
}
}
}
However, I have some things that bothers:
The required time to execute this script is very long, mostly exceeding the 90 seconds time.
Dirty database. I will have 730 row of data (per day) for each name, so my database 3 will have 730 * 78 person = 56.940 rows with duplicate date (2017-01-01 ... 2017-12-31 for Mr.AA, 2017-01-01 ...2017-12-31 for Mr.AB, etc...).
How can I optimize my code in table design and loading time?
Another method than file_get_contents is okay, I hope it's still PHP.

How to count number of rows with the same column data and display to table?

I have 2 tables, the 'department' and 'document'.
Table department
| doc_id | dept_name |
----------------------------------
| 1 | Information Technology|
| 2 | Software Development |
| 3 | Human Resource |
| 4 | Accounting |
| 5 | Support |
Table document
| doc_id | doc_name | author | description | department |
----------------------------------------------------------------------------
| 1 | Maps | User1 | sample | Information Technology |
| 2 | Audits | User3 | sample | Software Development |
| 3 | Image | User1 | sample | Information Technology |
| 4 | Papers | User4 | sample | Human Resource |
| 5 | Print Screen| User1 | sample | Software Development |
| 6 | Transaction | User3 | sample | Accounting |
| 7 | Graph | User1 | sample | Support |
| 8 | Excel | User1 | sample | Information Technology |
Now, I want to display the table with two columns: department and total_doc.
Output:
| department |total_doc|
-----------------------------------
| Information Technology| 3 |
| Software Development | 2 |
| Human Resource | 1 |
| Accounting | 1 |
| Support | 1 |
I want to display the total document inside the department and arrange them in ascending order.
Here's my query.(not sure)
SELECT department, count(doc_name) as 'total_doc' FROM tbl_document GROUP BY doc_name
I'm using MVC pattern in Codeigniter.
$this->db->select("department, count(doc_name) as 'total_doc'");
$this->db->from('document');
$this->db->group_by('doc_name');
Also, How can I display this in table? like using foreach in html?
You need to do group by with department not with doc_name.
$this->db->select("department, count(doc_name) as 'total_doc'");
$this->db->from('document');
$this->db->group_by('department');
$result = $this->db->get()->result();
Hope This will help you.
foreach ($result as $row)
{
echo $row->department."----".$row->total_doc;
}
here you go
SELECT dept_name,COUNT(td.department) FROM department d
LEFT JOIN tdocument td ON td.`department`=d.`dept_name`
GROUP BY td.`department` ORDER BY COUNT(td.`department`) DESC;
You want one line per department. IN SQL words: You want to group by department.
select department, count(*) as total_doc from document group by department;
(BTW: don't use single quotes for column aliases.)

How To Copy Database Records and Track Their New IDs

I have three tables: years, employees, positions. Suppose that I already have these data in those tables.
years:
----------------
| id | name |
----------------
| 1 | 2011 |
----------------
positions:
------------------------------
| id | name | year_id |
------------------------------
| 1 | Director | 1 |
| 2 | Manager | 1 |
------------------------------
employees:
---------------------------------------------------------
| id | name | position_id | year_id |
---------------------------------------------------------
| 1 | Employee A (Director) | 1 | 1 |
| 2 | Employee B (Manager) | 2 | 1 |
---------------------------------------------------------
========================================
The years table is a central point.
If I insert a new year record, I must also copy all positions and employees which are related to the previous year.
So if I insert year 2012 into the years table, the data is suppose to be like this:
years:
----------------
| id | name |
----------------
| 1 | 2011 |
| 2 | 2012 |
----------------
positions:
------------------------------
| id | name | year_id |
------------------------------
| 1 | Director | 1 |
| 2 | Manager | 1 |
| 3 | Director | 2 |
| 4 | Manager | 2 |
------------------------------
employees:
---------------------------------------------------------
| id | name | position_id | year_id |
---------------------------------------------------------
| 1 | Employee A (Director) | 1 | 1 |
| 2 | Employee B (Manager) | 2 | 1 |
| 3 | Employee A (Director) | 3 (?) | 2 |
| 4 | Employee B (Manager) | 4 (?) | 2 |
---------------------------------------------------------
NOTICE the question marks in the third and fourth row of employees table.
I use these queries to insert a new year and copy all related positions and employees:
// Insert new year record
INSERT INTO years (name) VALUES (2012);
// Get last inserted year ID
$inserted_year_id = .......... // skipped
// Copy positions
INSERT INTO positions (name, year_id) SELECT name, $inserted_year_id AS last_year_id FROM positions WHERE year_id = 1;
// Copy employees
INSERT INTO employees (name, position_id, year_id) SELECT name, position_id, $inserted_year_id AS last_year_id FROM employees WHERE year_id = 1;
The problem is at copying employees query. I can't find a method to get or track the new ID of positions.
Is there a simple method to do this?
Thank you very much.
Your data model is seriously flawed and probably needs a complete overhaul, but if you insist on copying the data like you describe, this should do the trick:
// Copy employees
INSERT INTO employees (name, position_id, year_id)
SELECT name, new_positions.id, $inserted_year_id AS last_year_id
FROM employees
JOIN positions AS old_positions ON old_positions.id = employees.position_id
AND old_positions.year_id = employees.year_id
JOIN positions AS new_positions ON new_positions.name = old_positions.name
AND new_positions.year_id = $inserted_year_id
WHERE employees.year_id = 1
I think you should read about database normalization. Copying the data leads to maintenance issues and erroneous reporting.
If you went with a different design like the following, then there would be nothing to insert, until an employee changes position, is terminated, or a position is discontinued. There are plenty of other ways to approach this, too, but you should minimize redundancy (i.e. have only one copy of each Employee), and then keep track of data that changes over time, separately. Also read about foreign keys before you try to implement something like this.
positions:
-- If you are keeping track of the years that each position is active,
-- using dates provides simplicity. Note: this design assumes that positions
-- are never reactivated after being deactivated.
------------------------------------------------
| id | name | DateActive | DateInactive |
------------------------------------------------
| 1 | Director | 01/01/2011 | |
| 2 | Manager | 01/01/2011 | |
------------------------------------------------
employees:
---------------------------------------------------------------
| id | name | DateHired | DateTerminated |
---------------------------------------------------------------
| 1 | Employee A | 01/01/2011 | |
| 2 | Employee B | 01/01/2011 | |
| 3 | Employee C | 01/01/2011 | 10/01/2012 |
---------------------------------------------------------------
EmployeePositionRelationships
--If you are keeping track of time that each employee held a position
-- Employee A has been a Director since 1/1/2011
-- Employee B was a Manager from 1/1/2011 to 10/6/2012. Then they became a Director
-- Employee B was a Manager from 1/1/2011 to 10/1/2012. Then they were terminated
--------------------------------------------------------
EmployeeId | PositionId | DateStarted | DateEnded |
--------------------------------------------------------
1 | 1 | 01/01/2011 | |
2 | 2 | 01/01/2011 | 10/6/2012 |
3 | 2 | 01/01/2011 | 10/1/2012 |
2 | 1 | 10/6/2012 | |
--------------------------------------------------------

Categories