Modifying dynamic column contents - sql

I am trying to create a new column inside a dynamic column.
My table Templates just has two columns: ID, Structure (blob)
I run this query:
UPDATE `Templates` SET `Structure` = COLUMN_ADD(`Structure`, 'general', '') where `Templates`.`ID` = 1
Structure Result (Using COLUMN_JSON for display):
{"general":""}
Then I run this query:
UPDATE `Templates` SET `Structure` = COLUMN_ADD(COLUMN_GET(`Structure`, 'general' as CHAR), 'Inner', 'value') WHERE `Templates`.`ID` = 1
Structure Result:
{"Inner":"value"}
The result I want after both queries:
{"general": {"Inner":"value"}}
How can I get a column added to the dynamic "general" column instead of replacing the contents?

First, here is what happens with your query.
MariaDB [test]> CREATE TABLE Templates (ID INT, Structure BLOB);
Query OK, 0 rows affected (0.24 sec)
MariaDB [test]> INSERT INTO Templates VALUES (1, COLUMN_CREATE('general',''));
Query OK, 1 row affected (0.05 sec)
MariaDB [test]> SELECT COLUMN_JSON(Structure) FROM Templates;
+------------------------+
| COLUMN_JSON(Structure) |
+------------------------+
| {"general":""} |
+------------------------+
1 row in set (0.00 sec)
At this point you have in Structure one dynamic column with name general and empty string as a value.
Then you do this:
UPDATE `Templates`
SET `Structure` = COLUMN_ADD(
COLUMN_GET(`Structure`, 'general' as CHAR),
'Inner',
'value'
) ...
Your COLUMN_GET gets the value of general dynamic column, which is an empty string, and uses it as the first argument for COLUMN_ADD. It's a useless exercise, because if you want to run COLUMN_ADD on an empty string, you can just say so in the query or use COLUMN_CREATE; and if you want to actually add something to the existing value of the blob, you need to use the name of the blob.
So, COLUMN_ADD works on an empty string -- in other words, creates a clean new value for Structure, discarding everything it had -- and adds a dynamic column with name Inner and value value. That's why you are getting this:
MariaDB [test]> SELECT COLUMN_JSON(Structure) FROM Templates;
+------------------------+
| COLUMN_JSON(Structure) |
+------------------------+
| {"Inner":"value"} |
+------------------------+
1 row in set (0.00 sec)
Apparently, what you want to do instead is to set the value of general column to a new dynamic column.
You don't need to fetch general column for that, because COLUMN_ADD(x,y,z) will replace the value if a column y already exists in blob x. But you need to construct a new dynamic column for the new value of general.
So, what you should do is
UPDATE `Templates`
SET `Structure` = COLUMN_ADD(
`Structure`,
'general',
COLUMN_CREATE('Inner','value')
) ...
This accounts for a more general case when Structure also contains other columns, not only general, and you want to preserve them. If it's not the case, and you want to make sure the blob contains only general, then you can do
UPDATE `Templates`
SET `Structure` = COLUMN_CREATE(
'general',
COLUMN_CREATE('Inner','value')
)

Related

UPDATE and REPLACE part of a existing column value with new column value

I am trying to update a existing column value with new value in sql table.
For example, My table has below data
table1:
ID
RequestName
1
Victor-123
2
Hello-123
3
Victor-124
4
Victor-125
5
Hi-123
6
Victor-126
In the above table I want to update Request Name column value wherever we have Victor, I want to replace with Victor-ID. For example
for ID 1 we have RequestName column value is Victor-123. I want to update it with Victor-ID-123 using Sql. I know we can do it with update sql statement, but if we have lot of data how to achieve that or replace 'Victor' with 'Victor-ID'. Since we might have different values in Request Name column. I want to update only column value with Victor to Victor-ID in table
Any help, I appreciate it
Thank you
UPDATE [tablename] SET [RequestName] = REPLACE(RequestName,'Victor','Victor-ID')
Here are two examples:
Example 1:
update table1
set RequestName = REPLACE(RequestName, 'Victor', 'Victor-ID')
where RequestName like 'Victor-%'
Example 2 (this one will let you use this for any name by changing the where clause):
update table1
set RequestName = LEFT(RequestName, CHARINDEX('-', RequestName) - 1) + '-ID-' + RIGHT(RequestName, LEN(RequestName) - CHARINDEX('-', RequestName))
where RequestName like 'Victor-%'
I don't believe example 1 actually requires the where clause though, as it should only affect those with "Victor". However, if you have something like "Victor1-123" that should not be changed, the where clause will prevent that.
Edit: Just occurred to me that example 1 can be adjusted to:
update table1
set RequestName = REPLACE(RequestName, 'Victor-', 'Victor-ID')
This will allow you to eliminate the where clause.

Unknown system variable 'ROWCOUNT' [duplicate]

Is there an easy way to INSERT a row when it does not exist, or to UPDATE if it exists, using one MySQL query?
Use INSERT ... ON DUPLICATE KEY UPDATE. For example:
INSERT INTO `usage`
(`thing_id`, `times_used`, `first_time_used`)
VALUES
(4815162342, 1, NOW())
ON DUPLICATE KEY UPDATE
`times_used` = `times_used` + 1
I know this is an old question, but the Google lead me here recently so I imagine others come here, too.
#chaos is correct: there is the INSERT ... ON DUPLICATE KEY UPDATE syntax.
However, the original question asked about MySQL specifically, and in MySQL there is the REPLACE INTO ... syntax. IMHO, this command is easier and more straightforward to use for upserts. From the manual:
REPLACE works exactly like INSERT, except that if an old row in the table has the same value as a new row for a PRIMARY KEY or a UNIQUE index, the old row is deleted before the new row is inserted.
Note this is not standard SQL. An example from the manual:
CREATE TABLE test (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
data VARCHAR(64) DEFAULT NULL,
ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
mysql> REPLACE INTO test VALUES (1, 'Old', '2014-08-20 18:47:00');
Query OK, 1 row affected (0.04 sec)
mysql> REPLACE INTO test VALUES (1, 'New', '2014-08-20 18:47:42');
Query OK, 2 rows affected (0.04 sec)
mysql> SELECT * FROM test;
+----+------+---------------------+
| id | data | ts |
+----+------+---------------------+
| 1 | New | 2014-08-20 18:47:42 |
+----+------+---------------------+
1 row in set (0.00 sec)
Edit: Just a fair warning that REPLACE INTO isn't like UPDATE. As the manual says, REPLACE deletes the row if it exists, then inserts a new one. (Note the funny "2 rows affected" in the example above.) That is, it will replace the values of all columns of an existing record (and not merely update some columns.) The behavior of MySQL's REPLACE INTO is much like that of Sqlite's INSERT OR REPLACE INTO. See this question for some workarounds if you only want to update a few columns (and not all columns) if the record already exists.

Moving data from one column to another in PostgreSQL

Sometimes, one might want to move some data from one column to another. By moving (in constrast to copying), I mean that the new column was originally null before doing the operation, and the old column should be set to null after doing the operation.
I have a table defined as such:
CREATE TABLE photos(id BIGSERIAL PRIMARY KEY, photo1 BYTEA, photo2 BYTEA);
Suppose there is an entry in the table where photo1 contains some data, and photo2 is NULL. I would like to make an UPDATE query wuch that photo1 becomes NULL and photo2 contains the data that was originally in photo1.
I issue the following SQL command (WHERE clause left out for brevity):
UPDATE photos SET photo2 = photo1, photo1 = NULL;
It seems to work.
I also tried it this way:
UPDATE photos SET photo1 = NULL, photo2 = photo1;
It also seems to work.
But is it guaranteed to work? Specifically, could photo1 be set to NULL before photo2 is set to photo1, thereby causing me to end up with NULL in both columns?
As an aside, this standard UPDATE syntax seems inefficient when my BYTEAs are large, as photo2 has to be copied byte-by-byte from photo1, when a simple swapping of pointers might have sufficed. Maybe there is a more efficient way that I don't know about?
This is definitely safe.
Column-references in the UPDATE refer to the old columns, not the new values. There is in fact no way to reference a computed new value from another column.
See, e.g.
CREATE TABLE x (a integer, b integer);
INSERT INTO x (a,b) VALUES (1,1), (2,2);
UPDATE x SET a = a + 1, b = a + b;
results in
test=> SELECT * FROM x;
a | b
---+---
2 | 2
3 | 4
... and the ordering of assignments is not significant. If you try to multiply-assign a value, you'll get
test=> UPDATE x SET a = a + 1, a = a + 1;
ERROR: multiple assignments to same column "a"
because it makes no sense to assign to the same column multiple times, given that both expressions reference the old tuple values, and order is not significant.
However, to avoid a full table rewrite in this case, I would just ALTER TABLE ... ALTER COLUMN ... RENAME ... then CREATE the new column with the old name.

Changing a column type from integer to string

Using PostgreSQL, what's the command to migrate an integer column type to a string column type?
Obviously I'd like to preserve the data, by converting the old integer data to strings.
You can convert from INTEGER to CHARACTER VARYING out-of-the-box, all you need is ALTER TABLE query chaning column type:
SQL Fiddle
PostgreSQL 9.3 Schema Setup:
CREATE TABLE tbl (col INT);
INSERT INTO tbl VALUES (1), (10), (100);
ALTER TABLE tbl ALTER COLUMN col TYPE CHARACTER VARYING(10);
Query 1:
SELECT col, pg_typeof(col) FROM tbl
Results:
| col | pg_typeof |
|-----|-------------------|
| 1 | character varying |
| 10 | character varying |
| 100 | character varying |
I suggest a four step process:
Create a new string column. name it temp for now. See http://www.postgresql.org/docs/9.3/static/ddl-alter.html for details
Set the string column. something like update myTable set temp=cast(intColumn as text) see http://www.postgresql.org/docs/9.3/static/functions-formatting.html for more interesting number->string conversions
Make sure everything in temp looks the way you want it.
Remove your old integer column. Once again, see http://www.postgresql.org/docs/9.3/static/ddl-alter.html for details
Rename temp to the old column name. Again: http://www.postgresql.org/docs/9.3/static/ddl-alter.html
This assumes you can perform the operation while no clients are connected; offline. If you need to make this (drastic) change in an online table, take a look at setting up a new table with triggers for live updates, then swap to the new table in an atomic operation. see ALTER TABLE without locking the table?

How to set up manually the next value of auto_increment?

I added some rows into the table manually and also I set up the ID (auto_increment) manually. Now when I try to add new row through my app into DB table, to DB table I am getting the error , that the created ID value already exist.
How can I set manually the next ID value (for example, in table I have to IDs, so how to tell to PostgreSQL, that the next ID should be counted since the number 3)?
http://www.postgresql.org/docs/current/static/functions-sequence.html
select setval('sequence-name', <new-value>);
You can get the sequence name from the the table definition:
id | integer | not null default nextval('id_seq'::regclass)
In this case the sequence is named 'id_seq'
Edit (10x to #Glenn):
SELECT setval('id_seq', max(id)) FROM table;
I think there is a simpler way:
ALTER SEQUENCE "seq_product_id" RESTART WITH 10