simplifying postgres queries - sql

Note: Asking to improve the working code.
My data column is as follows
{
"color":"red",
"toy":{
"id":27,
"name":"Truck",
"price":12,
"available":true
},
"quantity":"12"
}
In the above data, I want to set available to false and price to zero.
To do this I Am using the below code.
UPDATE toys
SET data=JSONB_SET(data, '{toy,available}','false')
WHERE data->'toy'->>'id'='27';
UPDATE toys
SET data=JSONB_SET(data, '{toy,price}','0')
WHERE data->'toy'->>'id'='27';
My question is it possible to update both values in a single query?
Thanks.

Sure:
UPDATE toys
SET data = jsonb_set(
jsonb_set(data, '{toy,available}', 'false'),
'{toy,price}',
'0'
)
WHERE data->'toy'->>'id'='27';

Related

how to update and append values to array in google spanner

I have a column with data type Array(String) in spanner. How can I append value to an array for update queries
I'm able to update the values using this command
update CarTable set models = ["BMW","HONDA"] WHERE year = "2020"
But the problem with this update is it overrides the previous values. I want to append these values to the ones that are already present. Is there any command that takes care of this requirement?
You can use the ARRAY_CONCAT function for that:
update CarTable set models = ARRAY_CONCAT(models, ["BMW","HONDA"]) WHERE year = "2020"

Active Record query for update between two ids in YII2 without using row query

I am noob in the YII2.
I am searching for an update query using Active Record in Yii2.
I need to update some record which are between two ids.
The Query:
UPDATE
table_name
SET status_name = 1
WHERE
id BETWEEN 1 AND 10;
What I have tried in Active Record:
$command = Yii::$app->db->createCommand('UPDATE table_name SET status_name = 1 WHERE id BETWEEN 1 AND 10 ');
$command->execute();
But I need Activerecord query without using row SQL queries.
You can use static updateAll method from Active Record:
TableName::updateAll(['status_name' => 1], 'id BETWEEN 1 AND 10');
Or query builder:
Yii::$app->db
->createCommand()
->update(
'table_name',
['status_name' => 1],
'id BETWEEN 1 AND 10'
)
->execute();
Like an another solution to question mentioned you can use Update counters:
Updating Counters
It is a common task to increment or decrement a column in a database table. We call these columns "counter columns". You can use updateCounters() to update one or multiple counter columns. For example,
$posts = TableName::find()->where(['between', 'id', "1", "10" ])->all();
$posts->updateCounters(['status_name' => 1]);
Note: If you use yii\db\ActiveRecord::save() to update a counter
column, you may end up with inaccurate result, because it is likely
the same counter is being saved by multiple requests which read and
write the same counter value.
Update:
Like mentioned in comments for Events like EVENT_AFTER_UPDATE to be occur You should do something like this:
$model = TableName::findOne()->where(['between', 'id', "1", "10" ])->all();
$model->status_name = new \yii\db\Expression('status_name + 1');
$model->save();
This issue was discussed here: Event EVENT_AFTER_UPDATE does not occur when updateCounters

Convert INSERT sequence into UPDATE sequence

i have a SQL INSERT sequence in PDO like:
INSERT INTO property (id,name,addres...) VALUES (:id,:name,:address...)
And i want to do a UPDATE sequence, with the same fields. The problem is that i have 150 fields and about 3 or 4 different sequences, so if i make the update syntax manually its probably that it takes a lot of time and a lot of mistakes, is there any "automatic" way to convert it?
Thank you a lot
The way I would do this, is have a function which dynamically builds the query based on key-value pairs passed in an array:
function updateTable($table, $values)
{
// Set the base query
$query = 'UPDATE ' . $table;
// Build the query with the key value pairs
foreach($values as $key=>$data) {
$query . ' SET ' . $key . ' = ' . $data . ' ';
}
// Execute your query here
...
}
Obviously you would need to bind your PDO objects on each iteration of the loop but I wanted to give you the basic layout of a loop to handle what you want to achieve, you could then call it like this:
updateTable('Products', { 'product_name' => 'Apple', 'product_price' => 100.00})
This would then build the query:
UPDATE Products SET product_name = 'Apple', product_price = 100.00
You could easily extend this query to provide a WHERE parameter so you can refine your UPDATE query - please remember this is currently in-secure so please spend some time implementing proper sanitsation over variables before committing to the DB!
Hope this helps.

Oracle: updating column IF ONLY it is not in condition of Merge statement

I'm having trouble with this Oracle Merge query.
merge into NEW_DOCTORS NP
USING OLD_DOCTORS MD
on (MD.SSN=NP.SSN OR MD.NPI=NP.NPI OR MD.PIN=NP.PIN)
WHEN MATCHED THEN
UPDATE SET
NP.othervalues=MD.othervalues
NP.PIN/SSN/NPI=MD.PIN/SSN/NPI (**update two of these three that did not return TRUE in the above ON condition)
WHEN NOT MATCHED THEN
insert(NP.SSN,NP.NPI,NP.PIN,NP.other_values)
values(MD.SSN,MD.NPI,MD.PIN,MD.other_values)
Is this possible? Thanks!
EDIT: I'm asking because I read somewhere that fields that are in the ON condition can't be updated. However I'm not sure if the author was talking only in context of the field that evaluates true or for all fields. I'm hoping there's someone who might have an idea about this, as well as any workarounds.
You can use CASE WHEN ... :
UPDATE SET
NP.othervalues=MD.othervalues
,NP.PIN = CASE WHEN (MD.SSN=NP.SSN OR MD.NPI=NP.NPI) THEN MD.PIN ELSE NP.PIN END
,--add here the 2 others
This means, when you have MD.SSN=NP.SSN OR MD.NPI=NP.NPI true, then update NP.PIN with MD.PIN else let the same value NP.PIN
Or you can do 3 differents MERGE, so it will be more readable.
EDIT
Thinking about it, if you update only when this is not the same value (cause it will join only on same value) you can directly update them with the MD table value.
Do that :
NP.othervalues=MD.othervalues
,NP.PIN=MD.PIN
,NP.SSN=MD.SSN
,NP.NPI=MD.NPI
If they match, the update will keep same value, if not it will update the value.

SQL - WHERE clause on each SET command in UPDATE?

I'm trying to create an SQL query in PHP to update a table.
Is it possible to have a different WHERE clause for each affected row?
eg something like:
UPDATE table
SET val=X WHERE someproperty = 1,
SET val=Y WHERE someproperty = 2
etc?
Any help appreciated. Thanks
Yes, you can with a CASE statement.
UPDATE table
SET val = CASE someproperty
WHEN 1 THEN x
WHEN 2 THEN y
....
ELSE
val
END
Now, there is concern that one CASE statement is less readable when compared to several UPDATE statements. There is a valid argument here. For example, when 1000 rows are being updated, it just feels and looks better to use several UPDATE statements rather than 1000 different conditions to a single CASE.
However, sometimes a CASE statement is more appropriate. If, for example, you are updating rows based on some trait, say the even or odd nature of a field's value the table, then a CASE statement is a wonderfully concise and maintainable way to update rows in the table without having to resort to a huge number of UPDATE statements that all share a specific type of logic. Take this for example:
UPDATE table
SET val = CASE MOD(someproperty, 2)
WHEN 0 THEN x
WHEN 1 THEN y
END
This expression takes the modulus of someproperty and, when 0 (even), assigns value x to val and, when 1 (odd), assigns value y to val. The greater the volume of data being updated by this statement, the cleaner it is compared to doing so by multiple UPDATE statements.
In short, CASE statements are sometimes just as readable/maintainable as UPDATE statements. It all depends on what you are trying to do with them.
EDIT: Added the ELSE clause to be extra safe. The OP may be interested in updating only specific rows so the rest should remain as they prior to the UPDATE.
EDIT: Added a scenario where the CASE statement is a more effective approach than multiple UPDATE statements.
You cannot have multiple WHERE clauses for any SQL statement, however you can use a CASE statement to accomplish what you are trying to do. Another option that you have is to execute multiple UPDATE statements.
Here is a sample using the CASE statement:
UPDATE table
SET val = (
CASE someproperty
WHEN 1 THEN X
WHEN 2 THEN Y
ELSE val
END
);
Here is a sample using multiple UPDATE statements:
UPDATE table SET val=X WHERE someproperty = 1;
UPDATE table SET val=Y WHERE someproperty = 2;
Nope. Make it two updates:
UPDATE table SET val=X WHERE someproperty = 1;
UPDATE table SET val=Y WHERE someproperty = 2;
On second thought, you could use sub-queries or the case statement...
UPDATE table SET val= ( case when someproperty = 1 then X when someproperty = 2 then Y else val END )
You may need to make that a sub query like this:
UPDATE table t1 SET val = ( select CASE when someproperty = 1 then X when someproperty = 2 then Y ELSE val END from table t2 where t1.primarykey = t2.primary key )
UPDATE TABLE
SET VAL CASE SOMEPROPERTY WHEN 1 THEN X WHEN 2 THEN Y END
A compact and easily scaleable way:
UPDATE table1 SET val=ELT(FIND_IN_SET(someproperty, '1, 2'), X, Y);
make the query this way:
$condition = array(1, 2);
$newvals = array('X', 'Y');
$query = "UPDATE table1 SET val=ELT(FIND_IN_SET(someproperty, '". implode(',', $condition). "', ". implode(', ', $newvals). ")";
Use prepare_query to avoid SQL syntax errors if you deal with string values.