I am running this SQL Query in PHP:
$sql="alter table callplandata change '".$_POST["col_name$y"]."' '".$_POST["col_newname$y"]."' ";
to alter column names but before it updates i want to check if the column name already exists and if it does to add a number on the end otherwise to just carry on updating
how can i do this using PHP?
Please, please, please, don't do this. This is about as unsafe a thing to do. However, I will say this: The ALTER TABLE syntax is worth a look:
ALTER TABLE <table name>
CHANGE [COLUMN] old_col_name new_col_name column_definition
Note that the column_definition bit is not optional.
Also, if you want to see if the fieldname given already exists:
SHOW COLUMNS FROM <table_name> /* or SHOW COLUMNS IN tbl */
Then, in PHP, depending on the extension you used, you do something like this:
$existingFields = array();
foreach ($resultSet as $row)
{
$existingFields[] = $row['Field'];
}
SHOW COLUMNS will also give you information concerning the type of each field, if it's a key, or even if it's an auto_increment value details, as ever, on the mysql website
So putting it all together:
$db = new PDO();//connect
$stmt = $db->prepare('SHOW COLUMNS IN callplandata WHERE Field = :field');
$bind = array(
':field' => $_POST['colname_new']
);
$stmt->execute($bind);
if ($row = $stmt->fetch())
throw new InvalidArgumentException($_POST['colname_new'].' already exists!');
$bind[':field'] = $_POST['colname_old'];
$stmt->closeCursor();//reset cursor, so we can re-use the statement
$stmt->execute($bind);//re-use statement
if (!($row = $stmt->fetch(PDO::FETCH_OBJ))
throw new InvalidArgumentException($_POST['colname_old'].' does not exist, cannot rename it!');
//very basic column definition construction here, needs more work, though!
$current = '';
$current = $row->Type. ' '.($row->Null == 'NO' ? 'NOT NULL ' : '').
($row->Default !== '' ? 'DEFAULT '.$row->Default.' ' : '').$row->Extra;
/**
* ADD CODE HERE TO SANITIZE THE NEW COLUMN NAME
* if you want to procede with this madness... I would urge you not to, though!
*/
$pdo->exec(
'ALTER TABLE callplandata
CHANGE '.$_POST['colname_old'].' '.$_POST['colname_new'].' './/rename
$current//add column definition
);
Disclaimer:
The code I posted here is meant to be purely academic. It should not be used, it's unsafe and incomplete. Please rethink what you are trying to do. Avoid, at all cost, using user data to alter how the server stores/structures the data!
Try this
SELECT *
FROM information_schema.COLUMNS
WHERE
TABLE_SCHEMA = 'db_name'
AND TABLE_NAME = 'table_name'
AND COLUMN_NAME = 'column_name'
In PHP
$result = mysqli_query("SHOW COLUMNS FROM `table` LIKE 'fieldname'");
$exists = (mysqli_num_rows($result))?TRUE:FALSE;
I think you need to specify datatype and default value also.
example
ALTER TABLE `ca_4_4_14` CHANGE `active` `is_active` ENUM('Y','N') CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT 'Y' NOT NULL;
Related
We recently updated our mariadb version and it is more strict on default column values, meaning if they are not set and not defined on insert it does not insert a new row. I am looking for a quick way to update all of the database columns that do not have a default value.
I imagine the code should look something like this, keep in mind this is only a pseudo code that I imagine and running this is not going to work:
$result = dbquery("SHOW TABLES");
while ($row = dbarray($result))
{
foreach ($row as $key => $table)
{
// this is the query where it should check
// if default value is set or not, but could not find information on how to do so
$result2 = dbquery("SHOW COLUMNS FROM $table WHERE DEFAULT IS NOT SET");
while ($column = dbarray($result2))
{
// SETTING A DEFAULT VALUE
dbquery("ALTER $table ALTER $column SET DEFAULT NULL");
}
}
}
NOTE: DISABLING STRICT MODE IS NOT A SOLUTION THAT I AM LOOKING FOR IN CURRENT TIME
Any ideas on how to select the columns where the default value is not set?
Thanks
Not providing a value for a nullable column is OK, so I suspect that you want to identify non-nullable column that have no default.
You could get that information from information_schema.columns:
select table_name, column_name
from information_schema.columns
where column_default is null and isnullable = 'NO'
From there on, you would need to decide which value should be used as a default; the answer does depends on your actual requirement and of the datatype of the column.
I have a function that shall modify column names in a MariaDB table. If I use MySQL or MariaDB version 10.5.2+ I can use the following simple query:
ALTER TABLE t1 RENAME COLUMN c_old TO c_new;
However, in older versions of MariaDB I am forced to use the more complicated CHANGE command, like this:
ALTER TABLE t1 CHANGE c_old TO c_new [data_definitions];
The data_definitions could be for example varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'Column for the username'. It is the creation of the data definition string that causes some trouble for me.
So, I wonder how I can get/create the data definitions string in PHP in order to make the correct query for changing column names. My code looks like this for the moment:
<?php
function rename_column($mysqli, $table, $current_name, $new_name) {
$data_definitions = // How do I find/get these in a simple way?
$sql = "ALTER TABLE {$table} CHANGE `{$current_name}` `{$new_name}` {$data_definitions}";
$res = $mysqli->query($sql);
if (!res) {
echo "'$sql' failed. Error: " . $mysqli->error;
return false;
}
return $res;
}
?>
I have thought of making a query like SHOW FULL COLUMNS FROM $table WHERE field = '$current_name' in order to read each data_definition and build a string for each definition, but I wonder if it can be solved in a simpler way?
How to get the next id in mysql to insert it in the table
INSERT INTO payments (date, item, method, payment_code)
VALUES (NOW(), '1 Month', 'paypal', CONCAT("sahf4d2fdd45", id))
You can use
SELECT AUTO_INCREMENT
FROM information_schema.tables
WHERE table_name = 'table_name'
AND table_schema = DATABASE( ) ;
or if you do not wish to use information_schema you can use this
SHOW TABLE STATUS LIKE 'table_name'
You can get the next auto-increment value by doing:
SHOW TABLE STATUS FROM tablename LIKE Auto_increment
/*or*/
SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES
WHERE table_name = 'tablename'
Note that you should not use this to alter the table, use an auto_increment column to do that automatically instead.
The problem is that last_insert_id() is retrospective and can thus be guaranteed within the current connection.
This baby is prospective and is therefore not unique per connection and cannot be relied upon.
Only in a single connection database would it work, but single connection databases today have a habit of becoming multiple connection databases tomorrow.
See: SHOW TABLE STATUS
This will return auto increment value for the MySQL database and I didn't check with other databases. Please note that if you are using any other database, the query syntax may be different.
SELECT AUTO_INCREMENT
FROM information_schema.tables
WHERE table_name = 'your_table_name'
and table_schema = 'your_database_name';
SELECT AUTO_INCREMENT
FROM information_schema.tables
WHERE table_name = 'your_table_name'
and table_schema = database();
The top answer uses PHP MySQL_ for a solution, thought I would share an updated PHP MySQLi_ solution for achieving this. There is no error output in this exmaple!
$db = new mysqli('localhost', 'user', 'pass', 'database');
$sql = "SHOW TABLE STATUS LIKE 'table'";
$result=$db->query($sql);
$row = $result->fetch_assoc();
echo $row['Auto_increment'];
Kicks out the next Auto increment coming up in a table.
In PHP you can try this:
$query = mysql_query("SELECT MAX(id) FROM `your_table_name`");
$results = mysql_fetch_array($query);
$cur_auto_id = $results['MAX(id)'] + 1;
OR
$result = mysql_query("SHOW TABLE STATUS WHERE `Name` = 'your_table_name'");
$data = mysql_fetch_assoc($result);
$next_increment = $data['Auto_increment'];
Use LAST_INSERT_ID() from your SQL query.
Or
You can also use mysql_insert_id() to get it using PHP.
Solution:
CREATE TRIGGER `IdTrigger` BEFORE INSERT ON `payments`
FOR EACH ROW
BEGIN
SELECT AUTO_INCREMENT Into #xId
FROM information_schema.tables
WHERE
Table_SCHEMA ="DataBaseName" AND
table_name = "payments";
SET NEW.`payment_code` = CONCAT("sahf4d2fdd45",#xId);
END;
"DataBaseName" is the name of our Data Base
Simple query would do
SHOW TABLE STATUS LIKE 'table_name'
For MySQL 8 use SHOW CREATE TABLE to retrieve the next autoincrement insert id:
SHOW CREATE TABLE mysql.time_zone
Result:
CREATE TABLE `time_zone` (
`Time_zone_id` int unsigned NOT NULL AUTO_INCREMENT,
`Use_leap_seconds` enum('Y','N') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'N',
PRIMARY KEY (`Time_zone_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1784 DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 ROW_FORMAT=DYNAMIC COMMENT='Time zones'
See the AUTO_INCREMENT=1784 at the last line of returned query.
Compare with the last value inserted:
select max(Time_zone_id) from mysql.time_zone
Result:
+-------------------+
| max(Time_zone_id) |
+-------------------+
| 1783 |
+-------------------+
Tested on MySQL v8.0.20.
SELECT id FROM `table` ORDER BY id DESC LIMIT 1
Although I doubt in its productiveness but it's 100% reliable
You have to connect to MySQL and select a database before you can do this
$table_name = "myTable";
$query = mysql_query("SHOW TABLE STATUS WHERE name='$table_name'");
$row = mysql_fetch_array($query);
$next_inc_value = $row["AUTO_INCREMENT"];
I suggest to rethink what you are doing. I never experienced one single use case where that special knowledge is required. The next id is a very special implementation detail and I wouldn't count on getting it is ACID safe.
Make one simple transaction which updates your inserted row with the last id:
BEGIN;
INSERT INTO payments (date, item, method)
VALUES (NOW(), '1 Month', 'paypal');
UPDATE payments SET payment_code = CONCAT("sahf4d2fdd45", LAST_INSERT_ID())
WHERE id = LAST_INSERT_ID();
COMMIT;
You can't use the ID while inserting, neither do you need it. MySQL does not even know the ID when you are inserting that record. You could just save "sahf4d2fdd45" in the payment_code table and use id and payment_code later on.
If you really need your payment_code to have the ID in it then UPDATE the row after the insert to add the ID.
What do you need the next incremental ID for?
MySQL only allows one auto-increment field per table and it must also be the primary key to guarantee uniqueness.
Note that when you get the next insert ID it may not be available when you use it since the value you have is only within the scope of that transaction. Therefore depending on the load on your database, that value may be already used by the time the next request comes in.
I would suggest that you review your design to ensure that you do not need to know which auto-increment value to assign next
use "mysql_insert_id()". mysql_insert_id() acts on the last performed query, be sure to call mysql_insert_id() immediately after the query that generates the value.
Below are the example of use:
<?php
$link = mysql_connect('localhost', 'username', 'password');
if (!$link) {
die('Could not connect: ' . mysql_error());
}
mysql_select_db('mydb');
mysql_query("INSERT INTO mytable VALUES('','value')");
printf("Last inserted record has id %d\n", mysql_insert_id());
?>
I hope above example is useful.
If return no correct AUTO_INCREMENT, try it:
ANALYZE TABLE `my_table`;
SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE (TABLE_NAME = 'my_table');
This clear cache for table, in BD
using the answer of ravi404:
CREATE FUNCTION `getAutoincrementalNextVal`(`TableName` VARCHAR(50))
RETURNS BIGINT
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
DECLARE Value BIGINT;
SELECT
AUTO_INCREMENT INTO Value
FROM
information_schema.tables
WHERE
table_name = TableName AND
table_schema = DATABASE();
RETURN Value;
END
using in your insert query, to create a SHA1 Hash. ex.:
INSERT INTO
document (Code, Title, Body)
VALUES (
sha1( getAutoincrementalNextval ('document') ),
'Title',
'Body'
);
Improvement of #ravi404, in case your autoincrement offset IS NOT 1 :
SELECT (`auto_increment`-1) + IFNULL(##auto_increment_offset,1)
FROM INFORMATION_SCHEMA.TABLES
WHERE table_name = your_table_name
AND table_schema = DATABASE( );
(auto_increment-1) : db engine seems to alwaus consider an offset of 1. So you need to ditch this assumption, then add the optional value of ##auto_increment_offset, or default to 1 : IFNULL(##auto_increment_offset,1)
For me it works, and looks simple:
$auto_inc_db = mysql_query("SELECT * FROM my_table_name ORDER BY id ASC ");
while($auto_inc_result = mysql_fetch_array($auto_inc_db))
{
$last_id = $auto_inc_result['id'];
}
$next_id = ($last_id+1);
echo $next_id;//this is the new id, if auto increment is on
SELECT AUTO_INCREMENT AS next_id FROM information_schema.tables WHERE table_name = 'table name' AND table_schema = 'database name of table name'
mysql_insert_id();
That's it :)
I wish to get the auto increment id from my db and call inside my controller.
The 'id' in db is primary key with auto increment.
I tried:
$id = $model->id;
$id = $model->find('id');
$id = $model->findByPK('id');
But the value is blank, any suggestion for me to get the correct id?
Reason why I need the id value is because I need id mix with other value and save into other column.
Thanks.
$newId = YourModel::find()->max('id') + 1;
AUTO_INCREMENT is a special value which may differ from the ID of the last record.
If records deleted, the AUTO_INCREMENT will still continue.
If records failed to insert, the AUTO_INCREMENT will still continue.
Assume you are using MySQL, you can see its value in phpMyAdmin.
Open a database, then a table.
Switch to the Operations tab.
Find the AUTO_INCREMENT field under Table options.
So you should obtain its value, especially when you depend on the AUTO_INCREMENT of your database.
For inserting one record, getting the LAST_INSERT_ID() could be an option. But I still don't prefer to do triple operations (insert, read ID, update). Better to minimize the I/O operations (read AUTO_INCREMENT, insert).
In my case, I need to import data from an Excel document. Surely, when performance is important, I cannot depend on the ActiveRecord model. So I use batchInsert() command.
I am adopting this answer for getting the AUTO_INCREMENT value in MySQL.
$lastModelId = Yii::$app->db->createCommand("
SELECT `AUTO_INCREMENT`
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'my_table'
")->queryScalar();
If using table prefix:
$lastModelId = Yii::$app->db->createCommand("
SELECT `AUTO_INCREMENT`
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = :TableName
")->bindValues([
':TableName' => MyModel::getTableSchema()->name,
])->queryScalar();
The easiest way would be to get the new ID after saving the record. After that you can do what you need and save it again. Sth like this:
<?
$model = new YourModel;
$model->field1 = 'some value';
$model->field2 = 'some value 2';
//...
$model->save();
// now you have the new ID and you can use it
$id = $model->id;
// do what you need e.g.
$model->field3 = $field2 + $id;
$model->save();
?>
this worked for me.
public static function getAutoIncrement($table_name)
{
$q = new Query();
$res = $q->select("AUTO_INCREMENT")
->from('INFORMATION_SCHEMA.TABLES')
->where("TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '" . $table_name . "'")
->one();
if($res)
return $res["AUTO_INCREMENT"];
return false;
//or use this
//$q = "SELECT `AUTO_INCREMENT` FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '" . $table_name . "'";
//$auto_increment = Yii::$app->db->createCommand($q)->queryScalar();
//return $auto_increment;
}
I found my own aswer:
$max = Yii::app()->db->createCommand()->select('max(id) as max')->from('TABLENAME')->queryScalar();
$id = ($max + 1);
print_r($id);
Thanks.
You are going about this the wrong way...
$model->id This is available if you have instantiated the $model prior so:
$model = new Model();
$id = $model->id; //this will work if id is the exact name of the column in db
$model->find('id') This finds elements in DB based on the id... but the syntax in wrong so it would throw an error
$model->findByPK('id') Again... find by pk returns a single row from DB if a match with the primary key (which you should have before making this call)
In conclusion, I would recommend the first way but do not forget to instantiate the model first. Otherwise, you can do something like...
$model = Model::model()->findByAttributes(array('some_attribute' => $attribute_value));
$id = $model->id;
Hope this helps!
Keep on coding!
Ares.
I trying update my plugin. So I must upgrade mysql_table. But when trying new column, program get exception.
This is my current table :
$sql = "CREATE TABLE {$table_name} (
say_id int(11) not null AUTO_INCREMENT,
customer_mail text not null,
customer_name text not null,
customer_messagge text not null,
messagge_date_time datetime not null,
PRIMARY KEY (say_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1";
require_once(ABSPATH . "wp-admin/includes/upgrade.php");
dbDelta($sql);
Now I am add colum more one table. I try Alter table, this working one time and add a column but one more refresh I get this error.
This is mycode
$wpdb->query("ALTER TABLE wp_customer_say ADD say_state INT(1) NOT NULL DEFAULT 1");
And this is my error
WordPress database error: [Duplicate column name 'say_state']
ALTER TABLE wp_customer_say ADD say_state INT(1) NOT NULL DEFAULT 1
I see this error and ı try this;
$query = $wpdb->query("select * from wp_customer_say");
$respond = mysql_num_fields( $query );
$column_array = array();
for($i = 0; $i < $respond ; $i++):
$column_array[] = mysql_field_name($query,$i);
endfor;
if( !in_array("say_state",$column_array) ):
$wpdb->query("ALTER TABLE wp_customer_say ADD say_state INT(1) NOT NULL DEFAULT 1");
endif;
and I get this error.
Warning: mysql_num_fields() expects parameter 1 to be resource, integer given in
Help please. Thank you.
Sorry bad english.
Use this query. I use only mysql-standred for get field name by fast query and this will solve your problem:
$row = $wpdb->get_results( "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'wp_customer_say' AND column_name = 'say_state'" );
if(empty($row)){
$wpdb->query("ALTER TABLE wp_customer_say ADD say_state INT(1) NOT NULL DEFAULT 1");
}
You can check column name exists in WordPress using below way,
$myCustomer = $wpdb->get_row("SELECT * FROM wp_customer_say");
//Add column if not present.
if(!isset($myCustomer->say_state)){
$wpdb->query("ALTER TABLE wp_customer_say ADD say_state INT(1) NOT NULL DEFAULT 1");
}
Best and correct way to add new column into the table if column not exists.
/*# Add status column if not exist */
global $wpdb;
$dbname = $wpdb->dbname;
$marks_table_name = $wpdb->prefix . "wpsp_mark";
$is_status_col = $wpdb->get_results( "SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `table_name` = '{$marks_table_name}' AND `TABLE_SCHEMA` = '{$dbname}' AND `COLUMN_NAME` = 'status'" );
if( empty($is_status_col) ):
$add_status_column = "ALTER TABLE `{$marks_table_name}` ADD `status` VARCHAR(50) NULL DEFAULT NULL AFTER `attendance`; ";
$wpdb->query( $add_status_column );
endif;
Just wanted to add that there's a slightly better way to do this than #Amandeep Wadhawan's answer.
register_activation_hook(__FILE__, 'install_tables');
function install_tables()
{
update_options('my_plugins_current_db_version', 0); // Replace 0 with whatever your final database version is
// Code here to create the final version of your database tables
}
add_action('plugins_loaded', 'update_databases');
public function update_databases()
{
global $wpdb;
$prefix = $wpdb->prefix;
$a_table_to_update = $prefix . $a_table_to_update;
$current_version = get_option('my_plugins_current_db_version', 0);
switch($current_version)
{
// First update
case 0:
// first update code goes here (alter, new table, whatever)
$current_version++;
case 1:
// next update code goes here
$current_version++;
}
update_option('my_plugins_current_db_version', $current_version);
}
You just have to make sure that your install_tables() function will always create the tables that reflect the final version number and sets the my_plugins_current_db_version option to the final version number.
Then in the update_databases() function you just have to make sure to increment $current_version before each subsequent case.
With this set-up you can blindly update without having to unnecessarily query to find out if columns or tables exist first - and less queries are always a good thing....especially if your update code is firing on the plugins_loaded hook.
It is also much cleaner, shows a clear upgrade path, and only executes necessary updates - so it is more efficient.
I really like Rikesh's option (even upvoted!), but I think to prevent hardcoding information which could change, such as $table_prefix from the wp-config.php file, this option is a safer bet.
// Replace `table_name` with the actual table name
$table = $table_prefix.'table_name';
// And use sprintf to pass the table name
// Alternatively, you can use $table instead of sprintf,
// if you use double quotes such as shown here
$myCustomer = $wpdb->get_row( sprintf("SELECT * FROM %s LIMIT 1", $table) );
// If you prefer not using sprintf, make sure you use double quotes
// $myCustomer = $wpdb->get_row( "SELECT * FROM $table LIMIT 1" );
// Replace "missing_field" by the column you wish to add
if(!isset($myCustomer->missing_field)) {
$wpdb->query( sprintf( "ALTER TABLE %s ADD phone2 VARCHAR(255) NOT NULL", $table) );
// Alternate example using variable
// $wpdb->query( "ALTER TABLE $table ADD phone2 VARCHAR(255) NOT NULL") );
}
Wrote a good solution, it works in all cases
$check_column = (array) $wpdb->get_results( "SELECT count(COLUMN_NAME) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME = '{$wpdb->prefix}my_table' AND COLUMN_NAME = 'some_name'" )[0];
$table_name = $wpdb->prefix . 'my_table';
$check_column = (int) array_shift($check_column);
if($check_column == 0) {
$wpdb->query(
"ALTER TABLE $table_name
ADD COLUMN `some_name` VARCHAR(55) NOT NULL
");
}
$myCustomer = $wpdb->get_row("SELECT * FROM wp_customer_say");
//Add column if not present.
if(!isset($myCustomer->say_state)){
$wpdb->query("ALTER TABLE wp_customer_say ADD say_state INT(1) NOT NULL DEFAULT '' ");
This code it will fail if you have no records in the database. Only works if you have at least one record saved in your database.