mysql update of a field and consequent usage of it - mysql

I have a pure theoretical question, with a nonsense example:
UPDATE mytable
binaryData = '___GIANT_BINARY_DATA___',
isBig = LENGTH('___THE_SAME_GIANT_BINARY_DATA___') > 1000000000
WHERE id = 22
Now, if my binary data is a "gillion bytes", i want to avoid to write it twice in the plain SQL
UPDATE mytable
binaryData = '___GIANT_BINARY_DATA___',
isBig = LENGTH(binaryData) > 1000000000
WHERE id = 22
I want to update a column field, then re-use it, using its column name, in the same query
or maybe is there a way to define an alias in the UPDATE syntax, like i can do with SELECT?
thank you in advance
(p.s. i'm also interested in to the equivalent INSERT syntax)

You can use a CROSS JOIN like so:
UPDATE mytable a
CROSS JOIN (SELECT '__GIANT_BINARY_DATA__' AS bindata) b
SET a.binaryDate = b.bindata,
a.isBig = LENGTH(b.bindata) > 1000000000
WHERE a.id = 22
Which will give you access to that same value in every row, and you only have to pass in the data once in the SQL statement string.

MySql is an oddity in that the SET statements are non-atomic, meaning that as soon as one column is assigned a new value, that new value will be reflected if it is used elsewhere in the update statement.
The following statements:
CREATE TABLE Swap (
a CHAR(1),
b CHAR(1)
);
INSERT INTO Swap (a, b) VALUES ('a', 'b');
UPDATE Swap SET a = b, b = a;
SELECT * FROM Swap;
Will result in b, b in MySql, but b, a in every other RBDMS that I'm aware of...
So for your question, you don't need to alias binaryData, because soon as it is updated, the updated value will be reflected in the isBig assignment statement.
However, it's probably a bad idea to rely on this behavior, since it is non-standard.

You can use a user variable:
set #content = '___GIANT_BINARY_DATA___';
UPDATE mytable
SET binaryData = #content,
isBig = LENGTH(#content) > 1000000000
WHERE id = 22;
set #content = NULL; -- free up memory

Related

How to use variables column name in where clause MySQL?

In this query:
SELECT *
FROM general_settings AS general_settings
JOIN settings_attribute AS settings_attribute ON settings_attribute.id = general_settings.settings_attribute_id
JOIN user_settings AS user_settings ON general_settings.user_settings_id = user_settings.id
WHERE
(settings_attribute.name = 'AAA' AND brand_settings.AAA <> general_settings.value)
OR
(settings_attribute.name = 'BBB' AND brand_settings.BBB <> general_settings.value)
OR
(settings_attribute.name = 'CCC' AND brand_settings.CCC <> general_settings.value)
;
I want a way using MySQL or Redshift to use settings_attribute.name as column name to avoid writing all the attribute names as a static in the query,
for example like this:
SELECT *
FROM general_settings AS general_settings
JOIN settings_attribute AS settings_attribute ON settings_attribute.id = general_settings.settings_attribute_id
JOIN user_settings AS user_settings ON general_settings.user_settings_id = user_settings.id
WHERE
brand_settings.#settings_attribute.name <> general_settings.value
;
No, this is not possible. In SQL, all identifiers (e.g. column names) must be explicit and fixed in the query at the time it is parsed, so the SQL engine can verify that the columns actually exist before it begins executing. It's not possible for a query to name different columns based on the string values it reads during execution.
What would happen if your settings_attribute.name contained 'XYZ' in some row, but there was no column by that name? It would be an error if you named a column that didn't exist, but in SQL that is checked at the time the query is parsed.

Updating multiple values at the same time SQL

I am trying to update multiple values at the same time,
Table values
UniqueRef, Name
1101, AA01
1102, AA02
1103, AA03
I want to update UniqueRef for all of 1101, 1102 and 1103 to different values e.g
1101 will be updated to 1101AB ect
how can I do this in bulk than one at a time?
Do it in a single UPDATE statement:
Seems like you need to update UniqueRef in a single pattern. So use following statement:
UPDATE YourTable SET name = CONCAT(UniqueRef, 'AB');
This will update all rows - in case you need to limit the scope use WHERE statement and define appropriate condition.
In case you need to use different values for each row use CASE statement in
UPDATE YourTable
SET name =
CASE
WHEN UniqueRef = 1101 THEN 'newValue'
WHEN UniqueRef = 1102 THEN 'anotherNewValue'
{nextStatements}
ELSE name
END
;
The scalable solution is to use UPDATE with a JOIN on a source for the new values (usually another table, but it can be an online view, such as below)
UPDATE
example
INNER JOIN
(
SELECT 1101 AS id, 'X' AS new_name
UNION ALL
SELECT 1102, 'Y'
)
AS update_map
ON update_map.id = example.uniqueRef
SET
example.name = update_map.new_name
Demo : https://dbfiddle.uk/g71hwuYG

updating a column blanks from values within the table

I want to update a table column where the field is blank with a zip code from within the column as the Name field is same for the 2 rows.
so the shipping zip blanks need to be filled with the same shipping zip where name is the same.
Thanks
The attached is the table screenshot
You didn't provide an actual table name. I will use table_name as a way to show you what to do. I am using the table_name twice, so each time I give it an alias (m & f). So that we can do compares
Slow answer
UPDATE table_name m
SET m.shipping_zip =
(SELECT f.shipping_zip
FROM table_name f
WHERE f.Name=m.Name and f.shipping_zip<>'')
WHERE m.shipping_zip = '';
Fast answer (but untested)
UPDATE table_name m, table_name f
SET m.shipping_zip = f.shipping_zip
WHERE m.Name=f.Name AND m.shipping_zip='' AND f.shipping_zip<>'';
This can be done like this
update `table` t, (select * from `table`
where shipping_zip is not null and shipping_zip != '')q
set t.shipping_zip = q.shipping_zip
where t.Name = q.Name;

MySQL: handle EMPTY SET in UPDATE statement

I have: something like
UPDATE table
SET field = (SELECT field FROM another_table WHERE id = #id);
Problem: SELECT field FROM another_table WHERE id = #id subquery can return one field or EMPTY SET.
Question: How to handle situation when subquery returns empty set?
Updated:
UPDATE table t
SET field = IF((SELECT field FROM another_table WHERE id = #id) IS NOT NULL, -- select field
(SELECT field FROM another_table WHERE id = #id), -- Problem #1: select field AGAIN!
(SELECT field FROM table WHERE id = t.id) -- Problem #2: try to not change value, so select the current field value!!
);
If function can be useful:
UPDATE table
SET field = if((SELECT field FROM another_table WHERE id = #id) IS NULL,true,false);
You can add the conditional:
WHERE (SELECT COUNT(*) FROM another_table WHERE id = #id) > 0
This will make sure that at least one row exists in another_table with the id. See my SQL Fiddle as an example.
Note: this may not be the most efficient because it does a count on another_table, and if it is greater than 1 it will do another SELECT (two sub-queries). Instead, you can do an INNER JOIN:
UPDATE table
INNER JOIN another_table ON table.id=another_table.id
SET table.field = another_table.field
WHERE another_table.id = #id;
See this SQL Fiddle. The reason why I saved this as a second option, is not all SQL languages can UPDATE with joins (MySQL can). Also, you need some way to relate the tables..in this case I said that the table.id we are updating is equal to another_table.id we are taking the data from.
NOTE The UPDATE statement will modify EVERY row in table and assign the same value to every row; that seems a little unusual.
To answer your question:
If you want to handle the "empty set" by not updating any rows in table, then one way to do this is with a JOIN to an inline view:
UPDATE table t
CROSS
JOIN (SELECT a.field
FROM another_table a
WHERE a.id = #id
LIMIT 1
) s
SET t.field = s.field
Note that if the inline view query (aliased as s) return an "empty set", then no rows in table will be updated, because the JOIN operation will also return an "empty set", meaning there are zero rows to be updated.

Updating a column twice in the same query

I want to know what this query will do:
UPDATE users SET
PaymentAmount = PaymentAmount + TempPaymentAmount,
PaymentDuration = PaymentDuration + TempPaymentDuration,
TempPaymentAmount = NULL,
TempPaymentDuration = NULL
WHERE UserID = 1234
You'll notice that I am trying to copy a value from temp column to the original column and nullify it at the same time. I am wondering if the query will do what I expect.
For instance values in row (UserId=1234) are following:
PaymentAmount = 10
PaymentDuration = 30
TempPaymentDuration = 40
TempPaymentAmount = 50
After the query execution:
PaymentAmount = PaymentAmount + TempPaymentAmount = 60
PaymentDuration = PaymentDuration + TempPaymentDuration = 70
TempPaymentAmount = NULL
TempPaymentDuration = NULL
MySQL 12.2.10. UPDATE Syntax
If you access a column from the table to be updated in an expression,
UPDATE uses the current value of the column. For example, the
following statement sets col1 to one more than its current value:
UPDATE t1 SET col1 = col1 + 1;
Also an interestign point:
The second assignment in the following statement sets col2 to the
current (updated) col1 value, not the original col1 value. The result
is that col1 and col2 have the same value. This behavior differs from
standard SQL.
UPDATE t1 SET col1 = col1 + 1, col2 = col1;
Should work, according to the docs (http://dev.mysql.com/doc/refman/5.0/en/update.html):
Single-table UPDATE assignments are generally evaluated from left to
right. For multiple-table updates, there is no guarantee that
assignments are carried out in any particular order.
So, if you run it, it should perform all SET queries one by one, thus using the original value first, then nullifying it.
Why don't you give it a try and execute it?
The answer is yes: When you use values from columns that you modify in the same query, the database engine will take the unmodified values while calculating the updated values.
It should do.. My understanding of what is actually happening is:#
UPDATE users SET
:New.PaymentAmount = :Old.PaymentAmount + :Old.TempPaymentAmount,
:New.PaymentDuration = :Old.PaymentDuration + :Old.TempPaymentDuration,
:New.TempPaymentAmount = NULL,
:New.TempPaymentDuration = NULL
WHERE UserID = 1234