This question already has answers here:
Insert NULL instead of empty string with PDO
(3 answers)
Closed last month.
I searched any possible help that can be found online but still the problem with INSERT NULL using PHP PDO persists.
The script is a csvupload script originally came from here Import CSV into MySQL
To make the story short, Let me present the possible cause..
if($linearray[4]=='Unknown')
$linearray[4]=null;
$linemysql = implode("','",$linearray);
$linemysql = "'".$linemysql."'";
$setsu->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$tsuika = $setsu->prepare("INSERT INTO tablename (SubAgentID, BookID, AgentID, SubAgentName, Risk, Area, CurrentBalance) VALUES ($linemysql)");
$tsuika -> bindValue(':Risk', null, PDO::PARAM_INT);
$tsuika ->execute();
Looking the code above, I explicitly set the field values on the prepare statment.
On phpmyadmin the Risk field accepts NULL, set the default value to NULL, and has no problems. But when doing INSERT with PHP the value it gets is 0. Why?
Before Inserting, I echoed it and if the field $linearray[4] contains Unknown, it converts it to NULL yielding, '' for that part.
table structure
CREATE TABLE IF NOT EXISTS `subagentdb` (
`SubAgentID` int(10) NOT NULL AUTO_INCREMENT,
`BookID` int(10) NOT NULL,
`AgentID` int(10) NOT NULL,
`SubAgentName` varchar(30) NOT NULL,
`Risk` float DEFAULT NULL,
`Area` varchar(20) NOT NULL,
`CurrentBalance` float NOT NULL,
PRIMARY KEY (`SubAgentID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ;
You're binding the value explicitly as PDO::PARAM_INT. Whatever value you pass will be cast to an int because of that. null casts to 0.
To actually bind an SQL NULL value, you need to bind the value as PDO::PARAM_NULL.
just use PDO::PARAM_NULL instead of PDO::PARAM_INT ? I think the NULL is converted to 0 (INT) instead of null value
If you back-up a and then restore the table, the null value becomes 0. The only way I found to correct this is after the create table, add "UPDATE table SET foo to null WHERE foo = 0".
Related
I have a text data type in a database that would like to enter true or false values. If I do using Mysqli or PDO with BindParam works correctly it adds 1 or 0 but when I try to use BindValue it only works true. False value is exchanged for an empty space.
try{
$conn = new PDO("mysql:host=localhost;dbname=name_db", "root", "");
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "INSERT INTO upload_meta (video_id, upload_key, upload_value) VALUES (:video_id,:upload_key,:upload_value)";
$temp = $conn->prepare($sql);
$temp->bindValue(':video_id', 11111111);
$temp->bindValue(':upload_key', 'exodo');
$temp->bindValue(':upload_value', false);
$temp->execute();
}catch(PDOException $e){
echo $e->getMessage();
}
This field will receive values of various types needing to be text.
CREATE TABLE `upload_meta` (
`meta_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`video_id` int(11) unsigned NOT NULL,
`upload_key` varchar(255) DEFAULT NULL,
`upload_value` varchar(255) DEFAULT NULL,
PRIMARY KEY (`meta_id`),
KEY `video_id` (`video_id`),
KEY `index_upload_key` (`upload_key`(191)),
CONSTRAINT `upload_meta_ibfk_1` FOREIGN KEY (`video_id`) REFERENCES `video` (`id_video`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
According to the documentation
The answer is in the documentation for bindParam:
Unlike PDOStatement::bindValue(), the variable is bound as a reference and will only be evaluated at the time that PDOStatement::execute() is called.
And execute
call PDOStatement::bindParam() to bind PHP variables to the parameter markers: bound variables pass their value as input and receive the output value, if any, of their associated parameter markers
Your case
Your database structure expects upload_value as varchar which is basically text/string. When you use bindParam it is working because it is passing the value of true or false i.e., 1 or 0
But when you use bindValue the reference is passed and then evaluated at the time of execution, and hence true is getting converted into 1 (string/text), but false is evaluated to "empty" string.
Solution
Either use bindParam or if you want to use bindValue you should update your database structure to accept boolean values for upload_value instead of varchar
A 5 min guide: https://w3guy.com/php-pdostatement-bindparam-bindvalue/
I am getting one error while creating table using MySQL. I am explaining my query below.
$sql="CREATE TABLE db_cron( ".
"id INT NOT NULL AUTO_INCREMENT, ".
"user_alert INT(11) NOT NULL DEFAULT NONE, ".
"status INT(11) NOT NULL DEFAULT NONE, ".
"PRIMARY KEY ( id )); ";
I am getting the below error:
#1064 - You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near 'NONE, status INT(11) NOT NULL DEFAULT NONE, PRIMARY KEY ( id ))'
at line 1
Here I need to create table with default value as none.
You have used too many quotes just to connect multiple string, it does not required.
Please remove those quotes and you also have to provide default value instead of NULL something like 0 OR any other value that you want.
However you can use below query to create table.
$sql = "CREATE TABLE `db_cron`( id INT NOT NULL AUTO_INCREMENT,
user_alert INT(11) NOT NULL DEFAULT 0,
status INT(11) NOT NULL DEFAULT 0,
PRIMARY KEY ( id ))";
above query will create table with default value 0 for user_alert and status
Hope this will helps you
Thanks & Regards.
1.You have applied unnecessary quotes.
2.You have NOT NULL along with DEFAULT NONE, which is not going to happen(You have to provide some value as default when using NOT NULL)
Do like below:-
$sql="CREATE TABLE db_cron(
id INT(11) NOT NULL AUTO_INCREMENT,
user_alert INT(11) NOT NULL DEFAULT 0,
status INT(11) NOT NULL DEFAULT 0,
PRIMARY KEY ( id )
)";
i don't know what i am doing wrong here but i have been trying to get this to work for hours. i just want it to create a table that doesn't exist. i made it as simple as i can make it and still it just returns false and doesn't change anything. please let me what i am doing wrong thank you in advance.
$conn=mysql_connect('localhost:3306', 'root', '');
mysql_select_db("test",$conn);
$sql = "CREATE TABLE IF NOT EXISTS 'works' (
`autoPlace` int(11) unsigned NOT NULL auto_increment,
`element` float(255) NOT NULL,
`month` tinyint(4) NOT NULL ,
`mday` tinyint(4) NOT NULL ,
`wday` char(12) NOT NULL ,
`time` smallint(6) NOT NULL,
PRIMARY KEY (`autoPlace`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8";
$thisKeepsReturningFalse= mysql_query($sql);
var_dump($thisKeepsReturningFalse);
When I tried to execute your query I got this error:
Incorrect column specifier for column 'element'
The problem is float(255) is not a valid declaration
It needs to be float(x) where x<=53, or you can use float(x,y) - see mysql docs here
Also, as pointed out in the comments, you have single quotes around works. Remove them or replace them with backticks.
After fixing these errors, I was able to successfully execute your query.
"CREATE" command in MySQL is not return value command so that it always return false(not like SELECT). To check if the command "CREATE" success or not, you can use "SHOW TABLES" to check after executing the "CREATE" command.
When you create a float element you must specify the decimals with a comma.And also the name of the table can't be with this format '' it must to be inside ``.
So in this example the query should be :
CREATE TABLE IF NOT EXISTS `works`
(
`autoPlace` int(11) unsigned NOT NULL auto_increment,
`element` float(255,0) NOT NULL,
`month` tinyint(4) NOT NULL ,
`mday` tinyint(4) NOT NULL ,
`wday` char(12) NOT NULL ,
`time` smallint(6) NOT NULL,
PRIMARY KEY (`autoPlace`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
Note how the float it's float(255,0) and not just 255. You must set this , 0 is the default
I am trying to dynamically insert 'NULL' into the database using PDO.
TABLE STRUCTURE:
CREATE TABLE IF NOT EXISTS `Fixes` (
`Id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'PK',
`CurrencyId` int(11) NOT NULL COMMENT 'FK',
`MetalId` int(11) NOT NULL COMMENT 'FK',
`FixAM` decimal(10,5) NOT NULL,
`FixPM` decimal(10,5) DEFAULT NULL,
`TimeStamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
KEY `CurrencyId` (`CurrencyId`),
KEY `MetalId` (`MetalId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=13 ;
PHP / PDO QUERY:
$sql = 'UPDATE
Fixes
SET
FixAM = :fixAM,
FixPM = :fixPM
WHERE
MetalId IN (SELECT Id FROM Metals WHERE Name = :metal) AND
CurrencyId IN (SELECT Id FROM Currencies Where Id = :currency)';
$stmt = $db->prepare($sql);
for ($i = 0; $i<3; $i++) {
$stmt->execute(array(
':metal' => 'Silver',
':fixAM' => $fix['FixAM'][$i],
':fixPM' => $fix['FixPM'][$i],
':currency' => ($i+1))
);
}
e.g. sometimes, the value for $fix['FixPM'][$i] is sometimes 'NULL'. How do I insert this into the database? When I run the query and then view the data in the database, this record shows 0.0000, and not null.
How do I insert NULL values using PDO? provides a few solutions.
I dont think I can use $stmt->execute(array( ':v1' => null, ':v2' => ... )) as per example because sometimes the item is null, and sometimes not. As such, I need to refer to the variable I have created $fix['FixPM'][$i] and make that null as and when needed
Thanks in advance.
This appears to me to be a(n unreported?) bug in PDO's prepared statement emulation:
the implementation of PDOStatement::execute() eventually invokes pdo_parse_params();
that, in turn, attempts to quote/escape values based on the relevant parameter's data type (as indicated by the $data_type arguments to PDOStatement::bindValue() and PDOStatement::bindParam()—all parameters provided as $input_parameters to PDOStatement::execute() are treated as PDO::PARAM_STR, as stated in the documentation of that function);
string-typed values are escaped/quoted by calling the relevant database driver's quoter() method irrespective of whether they are null: in the case of PDO_MySQL, that's mysql_handle_quoter(), which (eventually) passes the value to either mysqlnd_cset_escape_quotes() or mysql_cset_escape_slashes(), depending on the server's NO_BACKSLASH_ESCAPES SQL mode;
given a null argument, both of those functions return an empty string.
My opinion is that, prior to switching on the parameter's type (in step 2 above), pdo_parse_params() should set the type to PDO::PARAM_NULL if the value is null. However, some might argue that this would prevent type-specific handling of null values where appropriate, in which case the string case (in step 3 above) should definitely handle null values before proceeding with a call to the driver's quoter() method.
As an interim workaround, disabling prepared statement emulation is usually for the best anyway:
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);
I noticed the other day that I cannot bind variables when using PDO with ALTER TABLE for example the following example will not work,
$q = $dbc -> prepare("ALTER TABLE emblems ADD ? TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', ADD ? DATETIME NOT NULL");
$q -> execute(array($emblemDB, $emblemDB . 'Date'));
So is it necessary to use mysql_real_escape string and do it like below,
// ESCAPE NAME FOR MYSQL INSERTION
$emblemDB = mysql_real_escape_string($emblemDB);
// INSERT EMBLEM DETAILS INTO DATABASE
$q = $dbc -> prepare("ALTER TABLE emblems ADD " . $emblemDB . " TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', ADD " . $emblemDB . "Date DATETIME NOT NULL");
$q -> execute();
Or do I not need to add in mysql_real_escape_string? As the only thing the query can do is ADD columns?
Thanks
Depends. If you directly use user input in your query, you should use it. If you don't, the user could delimit the query and throw a DROP statement after it.
When a user would input:
somekindofname TINYINT(1) UNSIGNED NOT NULL DEFAULT '0'; DROP TABLE emblems --
Your query would become:
ALTER TABLE emblems ADD somekindofname TINYINT(1) UNSIGNED NOT NULL DEFAULT '0'; DROP TABLE emblems -- TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', ADD TINYINT(1) UNSIGNED NOT NULL DEFAULT '0' somekindofname; DROP TABLE emblems -- Date DATETIME NOT NULL
Your database will execute the ALTER TABLE, execute the DROP TABLE and ignore the comment at the end.