Update dynamic SQL table with history table - php

I was successful in implementing a table's history (for auditing) based on this answer that basically suggests to create two tables wherein one contains the current version and the other a table of versions with the real data:
CREATE TABLE dbo.Page(
ID int PRIMARY KEY,
Name nvarchar(200) NOT NULL,
CreatedByName nvarchar(100) NOT NULL,
CurrentRevision int NOT NULL,
CreatedDateTime datetime NOT NULL
CREATE TABLE dbo.PageContent(
PageID int NOT NULL,
Revision int NOT NULL,
Title nvarchar(200) NOT NULL,
User nvarchar(100) NOT NULL,
LastModified datetime NOT NULL,
Comment nvarchar(300) NULL,
Content nvarchar(max) NOT NULL,
Description nvarchar(200) NULL
My UPDATEs to static, non-dynamic fields are OK where the versioning is recognised correctly (rough pseudocode adapted from dev't code):
$sql_pagecontent = array(
'PageID' => // logic to get PageID
'Title' => $data['Title']
'User' => $data['User'],
'LastModified' => $this->get_date(),
'Comment' => $data['Comment'],
'Content' => $data['Content'],
'Description' => $data['Description']
);
$this->db->insert('PageContent', $sql_pagecontent);
$id_version = $this->db->insert_id();
$sql_page = array(
'CurrentRevision' => $id_version
);
if($type_version === 'UPDATE')
{
$this->db->where('ID', $page_id_to_replace);
$this->db->update('Page', $sql_page);
}
else
{
$this->db->insert('Page', $sql_page);
}
The problem is when I apply this to dynamic tables with UPDATE.
During UPDATE, I want to achieve the following, just similar to the non-dynamic tables (context of Page and PageContent):
a new PageContent row is INSERTed (new PageContent), a new row of CurrentRevision in Page is added
a new PageContent row is INSERTed (update of existing PageContent), the CurrentRevision in Page UPDATEd with this new row
deleted PageContents are removed from Page
NOTE I want each row of these dynamic tables preserved in both Page and PageContent if ever the user wants to check the changes so I just cannot do INSERT which will just flood the table.
I cannot seem to filter these dynamic values correctly with the current implementation.
Please advise on how to deal with this use case.
Solution
I am not sure if my current implementation of my said requirements is correct, feasible or recommended but it does the job:
get ID of current PageContent being modified
get ID of current Page being modified
delete all rows of Page that has the ID of #1
perform INSERT and apply UPDATE as type of action of PageContent
Number 3 is key to make sure whether existing rows are edited/deleted or new rows added are saved as the current version in Page. Number 4 puts this into place to make sure every row is recognised.

Related

INSERT part of sql with UPDATE ON DUPLICATE KEY doesn't work, updating does work

First off, forgive me the unsafe code, I will work on that later on.
For now this problem:
I have a page with a form to which a user can add fields and modify existing fields.
I sent the form and when the input is new I also create an empty hidden input field for the primary key column that's empty to add a new row to db. Only this row is not being created. When user modifies existing row it does work. So the update on duplicate key part works, but the Insert part for a new field does not work.
I already used print_r to check what the variables look like and indeed like I wanted for a new field footNoteID is empty and footNoteNL contains whatever user entered, and for a modified field footNoteID has the old primary key value and whatever was modified. So that looks alright.
Yet the Insert part for a new field does not work.
This is the code on the php page that processes the form:
// two posted arrays from a form with multiple input fields
$footNoteNL = $_POST['footNoteNL'];
$footNoteID = $_POST['checkfootNoteID'];
// looping through the arrays
for($j=0, $count = count($footNoteNL); $j<$count; $j++) {
$footNoteNLThis = $footNoteNL[$j];
$footNoteIDThis = $footNoteID[$j];
$sql4 = "INSERT INTO footnotes (footNoteID, albumID, addedDate, footNoteNL, footNoteEN) VALUES ('".$footNoteIDThis."', '92', '".$datum."' , '".$footNoteNLThis."', 0)
ON DUPLICATE KEY UPDATE footNoteNL = '".$footNoteNLThis."'";
$result = mysqli_query($conn, $sql4);
This is the form on the HTML side, and the jquery that adds the input and hidden field. This part works. I use brackets on the form field to create a posted array. Like said, when checking what gets posted it seems ok.
$(document).ready(function () {
$('.addButton').on('click', function () {
$(".footNoteContainer").prepend("<div><input type='hidden' name='checkfootNoteID[]' value=''><TEXTAREA NAME='footNoteNL[]'></TEXTAREA>
// and so on
The part of the form this gets prepended to:
foreach ($mysqli->query('SELECT * FROM footnotes WHERE albumID = '.$album_id.' ORDER BY addedDate ASC') as $row ) {
<TEXTAREA NAME='footNoteNL[]'>".stripslashes($row['footNoteNL'])."</TEXTAREA>
<input type=\"hidden\" NAME=\"checkfootNoteID[]\" VALUE=\"".stripslashes($row['footNoteID'])."\">
// and so on, just to show that here the field are non empty since they get pulled form db
and here is what a check looks like when adding a new field, and modifying an existing ones: "_newly added field value 9092_old input value"
So before the underscore of the newly created field, there is no value for $footNoteIDThis , which makes me expect a new row gets added to db. For the modified field there is the old key "9292" so that\s a duplicate and indeed that one gets updated ...
this is dump form db:
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";
--
-- Table structure for table `footnotes`
--
CREATE TABLE `footnotes` (
`footNoteID` int(111) NOT NULL,
`albumID` int(11) NOT NULL,
`addedDate` date NOT NULL,
`footNoteNL` text NOT NULL,
`footNoteEN` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Indexes for table `footnotes`
--
ALTER TABLE `footnotes`
ADD PRIMARY KEY (`footNoteID`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `footnotes`
--
Sorry for all the info, hopefully it makes sense, sorry for cumbersome method, but I really don't see why this doesn't work, although I suspect the problem lies in the db table settings or structure?

why it shows error for wpdb insert sql?

I'm trying simple code with 2 tables(1 customer may have 1 or more phone number):
$wpdb->insert('Customer',array('mtrname' => $_POST['amtrname'],
'test' => $_POST['atest'],
'password' => $_POST['apassword'] ));
Then trying to get the id_customer as FK for table Phones:
$lastid = $wpdb->insert_id;
Then insert:
$wpdb->insert('Phones',array('number' => $_POST['anumber'],
'id_customer' => $lastid ));
In DB it works but I get this error :
WordPress database error: [] INSERT INTO Phones (number,
id_customer) VALUES ('8', '63')
Why I have such an error? All I want to do is linking 2 tables with 1 foreign key as I have "1 to Many" relationship
Customer
- id_customer // primary key, autoincrement
- mtrname // a varchar
- test // a varchar
- password // a varchar
Phones
- id_phone // primary key, autoincrement
- number // a varchar
- id_customer // foreign key reference to Customer
I want to share the solution if someone needs it :
well, I found out that the error comes because I wrote both of these together:
$wpdb->show_errors();
$wpdb->print_error();
When I use just one of them, I don't get any error(I still don't know the logic behind but fine..).
Thanks for your comments and thank you 'Suhas Bachhav' for that hint.

EditableGrid, "addcolumn" loop

Trying to make a loop for EditableGrid code.
This is how it looks now.
$grid->addColumn('id', 'ID', 'integer');
$grid->addColumn('site', 'Site', 'string');
So if I need to add a new column to the page, I add a new column in MySQL database and also add a new row in this code, like:
$grid->addColumn('newcolumn', 'A brand new column', 'string');
In order to automatically add new columns to the page I want to make a loop, which gets inputs for the first argument (name of the field in the database) taken from the table:
CREATE TABLE price (
id INT(11) NOT NULL AUTO_INCREMENT,
site VARCHAR(50) NOT NULL,
and the other two arguments (label that will be displayed in the header and data type of the column in MySQL) taken from this table:
CREATE TABLE header (
header_name VARCHAR(50) NOT NULL,
header_type VARCHAR(50) NOT NULL,
Ok, think I found the solution. In order to create the loop, we create 2 queries, which are:
$get=$mysqli->query('SELECT header_name, header_type FROM header');
$get1=$mysqli->query('SHOW COLUMNS FROM price');
then we make a loop
while($row = mysqli_fetch_assoc($get) and $row1 = mysqli_fetch_assoc($get1)){
$grid->addColumn(''.$row1['Field'].'', ''.$row['header_name'].'', ''.$row['header_type'].'');}
I, guess, that's it. Also, if you need to exclude some of the columns, use this piece of code:
if($row1 == 'id' || $row1 == 'site')
continue;

Waht's the best way to use unique validation according to an attribute in a table

I'm using Laravel 5.1 , I've a model Customer which has many Vehicles.
I set validations for Vehicle model like this :
public static $Rules = array(
'code' => 'required|unique:vehicles',
'registernumber' => 'required|unique:vehicles'
);
Till now, all is fine : I can't insert two vehicles with the same code or registernumber.
What I want to do is :
Can I set a custom validation which allows me to insert unique code or registernumber value just for a given CustumerID ?
Example :
Customer1 :
Vehicle1: code1, registernumber1
Vehicle2: code2, registernumber2
(Here I can't insert for example two codes having 'code1' value with Customer1)
Customer2 :
Vehicle1: code1, registernumber1
Vehicle2: code5, registernumber5
(Here I can't insert for example two registernumbers having 'registernumber5' value with Customer2)
Any idea please ?
As long as the customer id is in that table. The way the unique validation rule works is as follows:
unique:
[table name, optionally with a connection name],
[the column you are checking for uniqueness, optional],
[the id of the row that will be ignored in the check (for example if you are updating a row, you want the row you are updating to not be included), optional],
[the column name that contains the id you are running the check against, optional],
[additional where clauses (where_column, where_value)]
So, if your table schema looks like this:
vehicle_id, code_number, registration_number, customer_id
And you only want to run the unique check for rows of the same customer, you can do this:
$customer_id = 'whatever';
$Rules = array(
'code' => 'required|unique:vehicles,code_number,NULL,vehicle_id,customer_id,'.$customer_id
);
That will run the check only on rows where('customer_id', $customer_id)
Syntax
ALTER TABLE `tablename`
ADD UNIQUE KEY `my_unique_key` (`colname1`, `colname2`);
In your example
ALTER TABLE `yourtable`
ADD UNIQUE KEY `unique_reg` (`customername`, `vehicle`, `code`, `regno`);
Try this but you should handle the db_error otherwise it affects the user experience

debugging a database query in the context of Drupal development

I am developing a dynamic web page using Drupal 7. I ran into a very strange problem. I have reduced my problem to a very small test case as follows:
The database side: I am using MySQL. I have two tables as defined here with a few sample data entries:
CREATE TABLE people (
pid INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(30) NOT NULL
);
INSERT INTO people VALUES (NULL, 'Joe');
INSERT INTO people VALUES (NULL, 'Ant');
INSERT INTO people VALUES (NULL, 'Tom');
CREATE TABLE event (
eid INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
pid INT(6) UNSIGNED NOT NULL,
event_desc VARCHAR(20) NOT NULL,
event_date DATE NOT NULL
);
INSERT INTO event VALUES (NULL, 1, '1p', '2015-10-01');
INSERT INTO event VALUES (NULL, 2, '1p', '2015-10-12');
INSERT INTO event VALUES (NULL, 2, '2p', '2015-10-00');
INSERT INTO event VALUES (NULL, 2, '3p', '2015-00-00');
INSERT INTO event VALUES (NULL, 3, '1p', '2010-07-18');
INSERT INTO event VALUES (NULL, 3, '2p', '2010-09-00');
Note the only interesting feature here is that the event table may contain incomplete event date in the format of '2015-10-00' when date is unknown and '2015-00-00' when both date and month are unknown. I understand this is legal in MySQL.
The Drupal 7 side: I create a custom module as follows:
<?php
/**
* Implements hook_menu().
*/
function test_menu() {
$items['test'] = array(
'type' => MENU_NORMAL_ITEM,
'title' => 'Test',
'description' => 'Test',
'page callback' => '_test_page',
'access callback' => TRUE,
'menu_name' => 'main-menu',
);
return $items;
}
function _test_page() {
$output = "";
$sql = "SELECT event.event_desc, event.event_date, people.name FROM event, ";
$sql .= "people WHERE event.pid=people.pid ORDER BY people.name";
$result = db_query($sql);
foreach ($result as $data) {
$output .= $data->name. " ". $data->event_desc. " ". $data->event_date. "<br>\n";
}
return $output;
}
Note that I create a page with a menu item 'Test'. The page performs a query and displays the result. Now the very strange part: when the event date is incomplete, the query gets the wrong data '0000-00-00' as shown in the screen capture below:
Some analysis:
This does not seem to be a problem with my SQL, because when I try the
identical query from mysql command line I can get the correct result.
This only happens when I join the two tables. If I simply query the 'event' table, I can get the correct result display in that Drupal page.
When passing the SQL from a standalone PHP script to the database via PDO, there's no problem.
I learned from Drupal's forum that the Date type is not used in Drupal core. So it may or may not be well supported.
Because the debugging isn't straight-forward to do, I decided not to pursue it any longer. The simplest way around the bug was to use VARCHAR(10) to store the Date information. By making that simple change, my web page can function properly. Of course I would lose the ability to use any Date-related functions.
'2015-00-00' is legal in mysql. I wonder if is legal in PHP. What is the data type of $data->event_date ? Just make sure to print it as string and not as a formatted date.

Categories