I need to update two columns in a table in mysql. I have written following code in ZF2 model
$sql = new Sql($dbAdapter);
$update = $sql->update();
$update->table($table_name)
->set(array('checksum' => '', 'mailed_status' => 0))
->where('id = ' . $record_id);
$statement = $sql->prepareStatementForSqlObject($update);
$statement->execute();
Here in the above code, checksum is varchar column and mailed_status is bit column. The above query only updates checksum field but the mailed_status remains same (previously 1)
When I was updating mailed_status as 1, it works. I mean it updates 0 to 1 but the vice versa is not working.
I have printed the query and found that it makes quote around digit like this: '0' and '1'.
But I am wondering here. '1' is working but '0' is not, why?
What is the proper solution for this? Temporarily I changed the bit data type to varchar(1) in mysql database's table.
Thanks
Thats because 0 is treated like a Null value when updating your database. Changing column type to varchar(1) it's simpler than override sql update method!
Related
We want to change the way we pass values from PHP to stored procedures (T-SQL). I only have minor experience with PHP but I will attempt to explain the process from discussions with our web developer.
Current Process
Example test table
In order to update a record, such as Field3 in this example, we would pass all existing values back to the stored procedure.
EXEC dbo.UpdateTest #ID = 1, #Field1 = 'ABC', #Field2 = 'DEF', #Field3 = 'GHI', #Field4 = 'JKL'
Lets say to update Field3, you must click a button. This would navigate to a new page which would run the stored procedure to update the data. As the new page is unaware of the values it has to run a SELECT procedure to retrieve the values before running an UPDATE.
The script would then redirect the user back to the page which reloads the updated data and the changes are reflected on screen.
New Process
What we would like to do is only pass the fields we want to change.
EXEC dbo.UpdateTest #ID = 1, #Field2 = 'DEF', #Field3 = 'GHI'
Our solution is simple. First we set all of the updatable fields to optional (so NULL can be passed). We then check to see if the parameter is NULL (is not passed), if it is then we ignore it and if it isn't we update it.
UPDATE
dbo.Test
SET
Field1 = NULLIF(ISNULL(#Field1,Field1),'-999')
,Field2 = NULLIF(ISNULL(#Field2,Field2),'-999')
,Field3 = NULLIF(ISNULL(#Field3,Field3),'-999')
,Field4 = NULLIF(ISNULL(#Field4,Field4),'-999')
WHERE
ID = #ID
However we still want the procedure to update the database record to NULL if a NULL value is passed. The workaround for this was to assign an arbitrary value to equal NULL (in this case -999), so that the procedure will update NULL if the arbitrary value (-999) is passed.
This solution is rather messy and, in my eyes, an inefficient way of solving the problem. Are there any better solutions? What are we doing wrong?
A huge thanks in advance to any replies
Valdimir's method is great as far as passing a flag variable to identify when the value is passed or not passed and his notes about arbitrarily picking a value are right on, but I would guess that there are some arbitrary values you may never have to worry about. such as -999 for a integer when you don't allow for negative numbers, or '|||||||' for a null string. Of course this breaks down some when you do want to use negative numbers but then you could potentially play around with numbers too big for a data type such as BIGINT as a parameter default -9223372036854775808 for an int.... The issue really comes down to your business case of whether values can or can not be allowed.
However if you go a route like that, I would suggest 2 things. 1) don't pass the value from PHP to SQL instead make that the default value in SQL and test if the parameter is the default value. 2) Add a CHECK CONSTRAINT to the table to ensure the values are not used and cannot be represented in the table
So something like:
ALTER TABLE dbo.UpdateTest
CHECK CONSTRAINT chk_IsNotNullStandInValue (Field1 <> '|||||||||||||||||||' AND Field2 <> -999)
CREATE PROCEDURE dbo.UpdateTest
#ParamId numeric(10,0)
,#ParamField1 NVARCHAR(250) = '|||||||||||||||||||'
,#ParamField2 INT = -99999 --non negative INT
,#ParamField3 BIGINT = -9223372036854775808 --for an int that can be negative
AS
BEGIN
DECLARE #ParamField3Value INT
BEGIN TRY
IF ISNULL(#ParamField3,0) <> -9223372036854775808
BEGIN
SET #ParamField3Value = CAST(#ParamField3 AS INT)
END
END TRY
BEGIN CATCH
;THROW 51000, '#ParamField3 is not in range', 1
END CATCH
UPDATE dbo.Test
SET Field1 = IIF(#ParamField1 = '|||||||||||||||||||',Field1,#ParamField1)
,Field2 = IIF(#ParamField2 = -99999,Field2,#ParamField2)
,Field3 = IIF(#ParamField3 = -9223372036854775808, Field3, #ParamField3Value)
WHERE
ID = #ParamId
END
The real problem with this method is the numeric data field allowing for negative numbers as you really don't have an appropriate way of determining when the value should be null or not unless you can pick a number that will always be out of range. And I definitely realize how bad of an idea the BIGINT for INT example is because now your procedure will accept a numeric range that it shouldn't!
Another method/slight variation of Vladimir's suggestion is to flag when to make a field null rather than when to update. This will take a little getting used to for your PHP team to remember to use but because these flags can also be optional they don't have to be burdensome to always include something like:
CREATE PROCEDURE dbo.UpdateTest
#ParamId numeric(10,0)
,#ParamField1 NVARCHAR(250) = NULL
,#MakeField1Null BIT = 0
,#ParamField2 INT = NULL
,#MakeField2Null BIT = 0
,#ParamField3 INT = NULL
,#MakeField3Null BIT = 0
AS
BEGIN
UPDATE dbo.Test
SET Field1 = IIF(ISNULL(#MakeField1Null,0) = 1,NULL,ISNULL(#ParamField1,Field1))
,Field2 = IIF(ISNULL(#MakeField2Null,0) = 1,NULL,ISNULL(#ParamField2,Field2))
,Field3 = IIF(ISNULL(#MakeField3Null,0) = 1,NULL,ISNULL(#ParamField3,Field3))
WHERE
ID = #ParamId
END
Basically if you are using the stored procedure to Update a table and it has nullable fields, I don't think I would recommend having the paramaters be optional as it leads to business cases/situations that can be messy in the future especially concerning numeric data types!
Your approach where you use a magic number -999 for the NULL value has a problem, as any approach with magic numbers have. Why -999? Why not -999999? Are you sure that -999 can not be a normal value for the field? Even if it is not allowed for a user to enter -999 for this field now, are you sure that this rule will remain in place in few years when your application and database evolve? It is not about being efficient or not, but about being correct or not.
If your fields in the table were NOT NULL, then you could pass a NULL value to indicate that this field should not be updated. In this case it is OK to use a magic value NULL, because the table schema guarantees that the field can't be NULL. There is a chance that the table schema will change in the future, so NULL can become a valid value for a field.
Anyway, your current schema allows NULLs, so we should choose another approach. Have an explicit flag for each field that would tell the procedure whether the field should be updated or not.
Set #ParamUpdateFieldN to 1 when you want to change the value of this field. Procedure would use the value that is passed in the corresponding #ParamFieldN.
Set #ParamUpdateFieldN to 0 when you don't want to change the value of this field. Set #ParamFieldN to any value (for example, NULL) and the corresponding field in the table will not change.
CREATE PROCEDURE dbo.UpdateTest
-- Add the parameters for the stored procedure here
#ParamID numeric(10,0), -- not NULL
-- 1 means that the field should be updated
-- 0 means that the fleld should not change
#ParamUpdateField1 bit, -- not NULL
#ParamUpdateField2 bit, -- not NULL
#ParamUpdateField3 bit, -- not NULL
#ParamUpdateField4 bit, -- not NULL
#ParamField1 nvarchar(250), -- can be NULL
#ParamField2 nvarchar(250), -- can be NULL
#ParamField3 nvarchar(250), -- can be NULL
#ParamField4 nvarchar(250) -- can be NULL
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SET XACT_ABORT ON;
BEGIN TRANSACTION;
BEGIN TRY
UPDATE dbo.Test
SET
Field1 = CASE WHEN #ParamUpdateField1 = 1 THEN #ParamField1 ELSE Field1 END
,Field2 = CASE WHEN #ParamUpdateField2 = 1 THEN #ParamField2 ELSE Field2 END
,Field3 = CASE WHEN #ParamUpdateField3 = 1 THEN #ParamField3 ELSE Field3 END
,Field4 = CASE WHEN #ParamUpdateField4 = 1 THEN #ParamField4 ELSE Field4 END
WHERE
ID = #ParamID
;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
-- TODO: process the error
ROLLBACK TRANSACTION;
END CATCH;
END
So, parameters of the procedure are not optional, but you use #ParamUpdateFieldN flags to indicate which parameters hold useful values and which parameters should be ignored.
EXEC dbo.UpdateTest #ID = 1, #Field1 = 'ABC', #Field2 = 'DEF', #Field3 = 'GHI', #Field4 = 'JKL'
and
EXEC dbo.UpdateTest #ID = 1, #Field2 = 'DEF', #Field3 = 'GHI'
Are both valid ways to make use of the same stored procedure with MsSql or Sybase. When you don't send the values, it is the same as sending a null. Unless you set a default in the stored procedure. In that case the default is used instead of the null.
Not enough reputation to just comment.
In my opinion your solution is good enough as long as the arbitrary value cannot be a normal value for any of the fields.
However, I'd consider passing and storing something else besides NULL (“N/A” for example) when a field should not have an “actual” value and it’s purposely updated from the client side.
I'm a noob in cakephp. Working on an opensource project. The issue is:
When I'm inserting a value for a certain table ( "is_adjusted" (tinyint)), the my php code executes successfully. But the table is only taking 0 or 1 as it's value. Sample code :
$reward = $ta_customer_reward->newEntity();
$string_reward = var_export($reward, true);
$reward->customer_email = $some_preset_xyz;
$reward->reward_amount = $some_preset_xyz;;
$reward->particulars = $some_preset_xyz;
.. .. ..
// This is_adjusted is the culprit.
$reward->is_adjusted = 2;
$reward = $ta_customer_reward->save($reward);
Now whenever I save (insert) this in db, this is stored as 1. I'm stuck for three days. Things I've checked:
No default value in db for is_adjusted.
No other function is overwriting that field.
*** 1.The reward object looked quite unusual to me. There is a property name dirty. I'm still studying this. But for now it seems to me as some cakephp db object structure.
This is cakephp v 3. xyz***
This is by CakePHP's design. CakePHP always see tinyint(1) as boolean hence it will always convert your value to true/false hence the 1/0.
To overcome this issue, use tinyint(2) instead for your column type. Remember to clear your model cache!
CakePHP data type documentation:http://book.cakephp.org/3.0/en/orm/database-basics.html#data-types
Blog post about this:http://blog.room34.com/archives/2649
Similar Q&A:CakePHP and tinyint as boolean
I want to make php code with SQL Update Statement in Codeigniter.
If I execution code in Codeigniter, the data in database will be updated too.
I want to update one column (ID_STATUS) but with several condition.
The connection column 'ID_STATUS' with column 'lama' and 'estimasi'
My table name is "pelayanan".
ID_STATUS is PK from table "status".
So, Column ID_STATUS in table "pelayanan" is foreign key from table "status".
I tried with this query, but, It isn't if else condition yet.
condition 1 :
UPDATE `dbhpl`.`pelayanan`
SET `pelayanan`.`ID_STATUS` = '1'
WHERE `pelayanan`.`LAMA` <> `pelayanan`.`ESTIMASI`;
condition 2:
UPDATE `dbhpl`.`pelayanan`
SET `pelayanan`.`ID_STATUS` = '2'
WHERE `pelayanan`.`LAMA` = `pelayanan`.`ESTIMASI`;
That is the query on mysql. But I want to convert that query to php code (Codeigniter).
How come It will be?
your first query is
UPDATE `dbhpl`.`pelayanan`
SET `pelayanan`.`ID_STATUS` = '1'
WHERE `pelayanan`.`LAMA` <> `pelayanan`.`ESTIMASI`;
convert it as follows:
$update_data=array('ID_STATUS'=>'1');
$this->db->where('LAMA <>','ESTIMASI');
$this->db->update('pelayanan',$update_data);
your second query is
UPDATE `dbhpl`.`pelayanan`
SET `pelayanan`.`ID_STATUS` = '2'
WHERE `pelayanan`.`LAMA` = `pelayanan`.`ESTIMASI`;
convert it as follows:
$update_data=array('ID_STATUS'=>'2');
$this->db->where('LAMA','ESTIMASI');
$this->db->update('pelayanan',$update_data);
I have remove database name. database name will be selected in connection and and did required to mentioned it here.
condition 3:
a. both LAMA and ESTIMASI are null.
b. LAMA is null
c. ESTIMASI is null
If you want to update all rows in the table, based on the values of LAMA and ESTIMASI, you could do that in one fell swoop with one UPDATE statement.
UPDATE `dbhpl`.`pelayanan` p
SET p.`ID_STATUS`
= CASE
WHEN p.`LAMA` = p.`ESTIMASI` THEN '2'
WHEN p.`LAMA` <> p.`ESTIMASI` THEN '1'
WHEN p.`LAMA` IS NULL AND p.`ESTIMASI` IS NULL THEN p.`ID_STATUS`
WHEN p.`LAMA` IS NULL THEN p.`ID_STATUS`
ELSE p.`ID_STATUS`
END
Note that assigning the current value of the ID_STATUS column back to the ID_STATUS column results in "no update".
Since the last two WHEN conditions return the same values as the ELSE, those could be removed. These were included just to illustrate possible handling of condition 3.
One small difference with this vs. the original is that it will attempt tto update every row in the table, including rows that have a NULL value in LAMA and/or ESTIMASI. That means any UPDATE triggers will be fired for those rows. To get exactly the same result as the original, you'd need to include a WHERE clause that excludes rows where LAMA is null or ESTIMASI is null. For example:
WHERE p.`LAMA` IS NOT NULL
AND p.`ESTIMASI` IS NOT NULL
As far as how to accomplish this same thing in PHP, someone else may be able to answer that. Personally, I'd just do it one SQL operation.
The ANSI-standard syntax is a bit verbose. A MySQL specific version that accomplishes the same thing is a bit shorter:
UPDATE `dbhpl`.`pelayanan` p
SET p.`ID_STATUS` = IFNULL((p.`LAMA`=p.`ESTIMASI`)+1,p.`ID_STATUS`)
FOLLOWUP
If LAMA and ESTIMASI are defined as NOT NULL, then you wouldn't have to deal with condition 3. (In the more general case, we don't necessarily have that guarantee, so I think it's better pattern to account for those conditions, even if they won't ever happen in our particular case.
For CodeIgniter ActiveRecord, you'd could try something like this:
$this->db
->set('ID_STATUS', 'IFNULL((`LAMA`=`ESTIMASI`)+1,`ID_STATUS`)', FALSE)
->update('`dbhpl`.`pelayanan`');
So I have an import/export module for OpenCart, but it's wiping the entire product option table before inserting new data...
I need to develop support for the 3rd party product options module I have, but in the meantime--I figure I'd just stop it from deleting an important column in my product options table.
In the product_option_value table, I have 'product_option,' 'product_id,' 'quantity' etc., and there's one column named 'info' that I want to NOT wipe. The method is below:
function storeOptionsIntoDatabase( &$database, &$options )
{
// find the default language id
$languageId = $this->getDefaultLanguageId($database);
// start transaction, remove options
$sql = "START TRANSACTION;\n";
$sql .= "DELETE FROM `".DB_PREFIX."product_option`;\n";
$sql .= "DELETE FROM `".DB_PREFIX."product_option_description` WHERE language_id=$languageId;\n";
$sql .= "DELETE FROM `".DB_PREFIX."product_option_value`;\n";
$sql .= "DELETE FROM `".DB_PREFIX."product_option_value_description` WHERE language_id=$languageId;\n";
$this->import( $database, $sql );
...more code...
}
I'm not that familiar with MySQL, but I want something to the effect of:
$sql .= "DELETE FROM `".DB_PREFIX."product_option_value` WHERE column != 'info';\n";
Thanks!
Edit:
I tried Michael's suggestion to use UPDATE and explicitly setting them all to NULL... but that returned this error:
Error: Duplicate entry '0' for key 1
Error No: 1062 UPDATE
oc_product_option_value SET
product_option_value_id=NULL,
product_option_id=NULL,
product_id=NULL, quantity=NULL,
subtract=NULL, price=NULL,
prefix=NULL, sort_order=NULL,
weight=NULL, sku=NULL, image=NULL
I tried taking out the primary key:
$sql .= "UPDATE
".DB_PREFIX."product_option_value
SET product_option_id=NULL,
product_id=NULL, quantity=NULL,
subtract=NULL, price=NULL,
prefix=NULL, sort_order=NULL,
weight=NULL;\n";
but I get:
Error: Duplicate entry '1' for key 1
Error No: 1062 INSERT INTO
`oc_product....
Edit:
Okay, so I removed the 'primary_key' field from the INSERT... and I got no error messages from the upload. But when I view a product that product options, I get this message the top of my page:
Notice: Undefined index: name in
/httpdocs/ocart/catalog/model/catalog/product.php
on line 418Notice: Undefined index:
name in
/httpdocs/ocart/catalog/model/catalog/product.php
on line 418Notic.... it repeats
Make sure I understand: You want to clear values from all columns in the table product_option_value except for the column info ? If that's what you want, then the following may work. Please don't run it before we're clear on what you're trying to do!
DELETE FROM syntax implies deleting from a table name, not a column name. What you'll need to do instead is to UPDATE your rows to set all columns except the one you intend to keep to be either NULL or empty or their default value.
Don't forget to add a WHERE condition if you need to keep some rows as they are without modifying them! Without a WHERE, this query will NULL out all columns specified in the whole table.
UPDATE product_option_value
SET
product_option = NULL,
product_id = NULL,
quantity = NULL,
etc...
WHERE (some where condition if you need one)
I'm adding a second answer, taking a completely different approach which avoids SQL problems.
Export your table as a comma-separated text file. You can do this with phpmyadmin, or MySQL Workbench.
Open your CSV in a spreadsheet
Clear out the columns you want to clear out.
Save as a new CSV
Import the CSV back into your database using phpmyadmin, Workbench, or the LOAD DATA LOCAL INFILE syntax.
I'm using SQLite 3 with PHP.
The SQLite table consists of 2 INTEGER and one FLOAT column. When saving data into this table using PHP floats are not saved correctly (default value is stored instead). The two integer columns are saved. Any ideas what could be wrong? Thank you.
Simplified code that actually works correctly:
$conn = new SQLite3('dbFileName');
$conn->query("CREATE TABLE data (
id INTEGER NOT NULL DEFAULT 0 ,
ts INTEGER NOT NULL DEFAULT 0 ,
value FLOAT NOT NULL DEFAULT 0
);"
);
$conn->query("REPLACE INTO data(id,ts,value) VALUES ('1','1234567890','12.1')");
-> 1|1234567890|0
This is just a suggestion, seeing as I have never used SQLite, but are you sure the numbers should be quoted? That seems somewhat odd to me.
Try:
$conn->query("REPLACE INTO data(id,ts,value) VALUES (1, 1234567890, 12.1)");
Sqlite data types are typeless, so your queries have to work:
all the following queries works for me
REPLACE INTO data(id,ts,value) VALUES ('1','1234567890','12.1');
REPLACE INTO data(id,ts,value) VALUES ('1','1234567890','12,123')
REPLACE INTO data(id,ts,value) VALUES ('1','1234567890','abc');
Check your PHP variable, you might have a bug and you pass a null variable.