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.
Related
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?
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;
I have a table with a lot of columns. I have a function that duplicates my record into a new row with an updated auto-incremented ID.
The function works perfectly however, on some of my INT columns, sometimes I have a NULL as the default. When the record is duplicated, it turns my NULL placement into a 0.
I'm assuming it's because I am doing '" . value . "'
Could anyone help me figure out how I could make NULL values be inserted as " . NULL . " and keep my other values as '" . value . "'?
EDIT I'm having trouble differentiating a null and a blank value. I've tried empty() and is_null() and a varchar with no value and an INT with a NULL value isn't showing a difference
note: I understand that I am using an outdated mysql extension. For right now, I'm just trying to process my null variables correctly.
function duplicateRow($table, $id_field, $id_value)
{
// copy content of the record you wish to clone
$entity = mysql_fetch_array(mysql_query("SELECT * FROM {$table} WHERE {$id_field}={$id_value}"), MYSQL_ASSOC) or die("Could not select original record");
// set the auto-incremented id's value to blank. If you forget this step, nothing will work because we can't have two records with the same id
$entity[$id_field] = "";
// insert cloned copy of the original record
mysql_query("INSERT INTO {$table} (".implode(", ",array_keys($entity)).") VALUES ('".implode("', '",array_values($entity))."')") or die(mysql_error());
//returns the new id
return mysql_insert_id();
}
You don't need to fetch the data into PHP only then to send it back to MySQL: INSERT ... SELECT is a single SQL command that enables the whole shebang to take place natively within the database.
However, you need to exclude the $id_field from the operation, so you can't use the * wildcard but must instead explicitly list the column names. This adds some complexity, especially to perform the operation in a safe, injection-proof way:
function duplicateRow($table, $id_field, $id_value)
{
// prevent SQL injection
$enc_map = array(
'utf8' => 'UTF-8',
'latin1' => 'Windows-1252' // etc.
);
mb_regex_encoding($enc_map[mysql_client_encoding()]);
$table_safe = '`'.mb_ereg_replace('`', '``', $table ).'`';
$id_field_safe = '`'.mb_ereg_replace('`', '``', $id_field).'`';
$id_value_safe = mysql_real_escape_string($id_value);
// fetch column names
$fields = array();
$qry = mysql_query("SHOW COLUMNS FROM $table_safe");
while ($row = mysql_fetch_assoc($qry))
if ($row['field'] != $id_field)
$fields[] = '`'.mb_ereg_replace('`', '``', $row['field']).'`';
$fields_safe = implode(',', $fields);
// duplicate the record
mysql_query("
INSERT INTO $table_safe
($fields_safe)
SELECT $fields_safe
FROM $table_safe
WHERE $id_field_safe = '$id_value_safe'
");
//returns the new id
return mysql_insert_id();
}
Note that the ancient ext/mysql extension has been deprecated and its use in new code has been discouraged for years. You should seriously consider switching to either MySQLi or PDO.
What is your MySQL Version? some versions of MySQL (5.5 and earlier if I'm not mistaken) convert null values to empty for string fields and 0 to int fields.
You have to force null value or update to MySQL 5.6
I ended up making a foreach statement that checked to see if my value was null and changed the query a little bit. This may not be the greatest, the right, or practical way to do this but it works. If anyone has any suggestions, they are 100% appreciated!
The reason I kept my function mostly the same is I needed to use this for multiple large tables. So I didn't know exactly what the fields were going to be.
function duplicateRow($table, $id_field, $id_value)
{
// copy content of the record you wish to clone
$entity = mysql_fetch_array(mysql_query("SELECT * FROM {$table} WHERE {$id_field}={$id_value} AND snapshot=0"), MYSQL_ASSOC) or die("Could not select original record");
foreach ($entity as &$value) { if(is_null($value) == true) { $value = "NULL"; } else { $value = "'$value'"; } }
// set the auto-incremented id's value to blank. If you forget this step, nothing will work because we can't have two records with the same id
$entity[$id_field] = "'";
// insert cloned copy of the original record
$query = "INSERT INTO {$table} (".implode(", ",array_keys($entity)).") VALUES ('".implode(", ",array_values($entity)).")";
mysql_query($query) or die(mysql_error());
//returns the new id
return mysql_insert_id();
}
i want to store the value of a checkbox into my sql database, basically i want to save the default value if it is checked or not.. i am not sure what this would save either true or false?
<div><input type="checkbox" value="Yes" name="chk"/> Yes! I will come!</div>
should I insert into my table like this?
'$_POST[chk]'
Thank you
$_POST[chk] will return the text Yes, in your case, if checked, and won't set it at all if not. Knowing this, you can set the db field how you want, say 1 or 0 for tinyint type:
$chk = isset($_POST['chk']) ? 1 : 0;
$sql = "update tbl set chk1 = $chk";
I would recommend using tinyint(1) datatype for the column in which you plan on storing whether a checkbox has been selected or not.
ALTER table `my_table` ADD COLUMN `my_checkbox_col` tinyint(1) unsigned NOT NULL default 0;
Yes. And sanitize input before you insert.
Use
if(isset($_POST[chk]) ) {
$chk = (string) $_POST[chk];
}
No.
You should do it like this
if(isset($_POST['chk'])):
$chk = mysql_real_escape_string($_POST['chk']);
else:
$chk = 0;
endif;
$sql = "INSERT INTO table VALUES ('$chk')";
Then insert the field as '$chk'.
This is the safest method and it's best to remove the [' '] part of a variable as it may affect your SYNTAX when adding it to the table.
I have a column in a table which is has the data type of an integer. What I had in mind was that values added into that column will be either 0 - N, or just blank as in an empty variable (see below), but I'm not sure that this is possible?
if($resource) {
$resource = $id - 2;
} else {
$resource = "";
}
$result = mysql_query("INSERT INTO table (...,resource,...) VALUES (...,'$resource',...)");
If not, could I instead use the data type of VARCHAR, and then say:
if($resource) {
$resource = $id - 2;
} else {
$resource = "INVALID";
}
In that case, is there any conversion functions I'd have to do when extracting values from the column resource, or would numbers automatically be treated as integers?
If the field should be "white" for any reason, I think you should mark it as NULLABLE and use word NULL (not INVALID)
If a column is a number, never use a varchar, you will loose a lot of things (also, an int is smaller than a varchar)
EDIT 1: Code snippet to allow null values on column:
ALTER TABLE mytable MODIFY mycolumn INT;
If you specify it as:
ALTER TABLE mytable MODIFY mycolumn INT NOT NULL;
It will be not nullable, so it should be nullable by default if you didn't declare it differently
EDIT 2: Important note, the column must not be UNIQUE otherwise the value will be not nullable!