How to update based on json keys? - json

I have a table of an app setting that looks like this:
Code | Value |
---------------------
MAC_ADDR | 'SAMPLE'|
PC_OPT | 0 |
SHOW_ADDR | 1 |
Then I'm receiving a json in my trigger function like this:
{MAC_ADDR: 'NEWADDR', PC_OPT: 1, SHOW_ADDR: 0}
How do I perform an update based on all the keys from my json?

you can just use json_populate_record, eg:
t=# create table tj("MAC_ADDR" text, "PC_OPT" int, "SHOW_ADDR" int);
CREATE TABLE
t=# insert into tj select 'SAMPLE',0,1;
INSERT 0 1
t=# select * from tj;
MAC_ADDR | PC_OPT | SHOW_ADDR
----------+--------+-----------
SAMPLE | 0 | 1
(1 row)
t=# update tj set "MAC_ADDR"=j."MAC_ADDR", "PC_OPT"=j."PC_OPT", "SHOW_ADDR"=j."SHOW_ADDR"
from json_populate_record(null::tj,'{"MAC_ADDR": "NEWADDR", "PC_OPT": 1, "SHOW_ADDR": 0}') j
where true;
UPDATE 1
t=# select * from tj;
MAC_ADDR | PC_OPT | SHOW_ADDR
----------+--------+-----------
NEWADDR | 1 | 0
(1 row)
keep in mind - you did not specify PK or other column to update rows so all rows will be updated in example above. Which suits your data sample, but would not in case of more data
Update
I misunderstood the question, in (code, value) table it's even easier, eg:
update some_tbl
set "Value" = '{"MAC_ADDR": "NEWADDR", "PC_OPT": 1, "SHOW_ADDR": 0}'::json->'MAC_ADDR'
where "Code"='MAC_ADDR'
o again, using the code above you can map update with json keys...

Related

SQL code to call all the columns from a Tb expect one column which can be called using As?

My current code is given below. I wanted to call all the columns from the table using * but the idcastncrew column name should display like castncrewid. In the requirement code, it's not working though, I wish there was a solution for my requirement such as the sample Requirement code.
Current code:-
SELECT idcastncrew AS castncrewid,castncrewname,castncrewtype,castncrewrole,imagelink,vendor,mode FROM subscriber;
Requirement :-
SELECT idcastncrew AS castncrewid, * FROM subscriber;
The closest I think you can get is to have the renamed column twice, once with the new name and once with the old name.
While MySQL does not allow * after an aliased column (causing your second code snippet to give an error), it does allow table.* anywhere...
SELECT idcastncrew AS castncrewid, subscriber.*
FROM subscriber;
To re-iterate; you'll still get a idcastncrew column, but you will ALSO get a castncrewid column.
There is no way to say don't include *this* column when using * in MySQL
https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=c69c537e46ad29e3c0c8c03d3ebd1bf7
You can alias columns when you alias the table, example as follows
MariaDB [DEV]> create table xxx (id int, str varchar(20));
MariaDB [DEV]> insert into xxx values (1, 'hi');
MariaDB [DEV]> insert into xxx values (2, 'Hello');
MariaDB [DEV]> insert into xxx values (3, 'World');
MariaDB [DEV]> insert into xxx values (4, 'Goodbye');
MariaDB [DEV]> select a.id as id1, a.* from xxx a order by 1;
+------+------+---------+
| id1 | id | str |
+------+------+---------+
| 1 | 1 | hi |
| 2 | 2 | Hello |
| 3 | 3 | World |
| 4 | 4 | Goodbye |
+------+------+---------+

INSERT INTO WHERE LIKE Condition

I am working on a trigger which needs INSERT INTO with WHERE LIKE logic.
I have one table :
Tabel test;
idDocument = varchar(32) idUnit = varchar(3)
-----------------------------
| idDocument | idUnit |
-----------------------------
| AA/2021/KK | NULL |
| AA/2021/JJ | NULL |
| BB/2021/KK | NULL |
| CC/2021/JB | NULL |
-----------------------------
How to INSERT INTO using WHERE LIKE Condition and myquery still ERROR.
myquery :
INSERT INTO test ('idUnit') Values ('111') WHERE idDocument LIKE
'%KK%'
Normally to update existing rows with a new value you'd do something like this:
UPDATE test SET idUnit='111' WHERE idDocument LIKE '%KK%'
This will not insert data, it will only alter existing data.
Note:
INSERT is specifically for adding new rows of data
UPDATE is exclusively for updating existing rows with new data
You can't conditionally add new rows. You either add them or you don't. You can conditionally update or delete them.
Don't think about it in terms of inserting new data, always think in terms of rows and columns which is how SQL works.

mysql On Duplicate value in field, insert new row with new value

I want to add a new record in a table if duplicate value enters in a unique field. I don't want to update the existing one but want to add a new record by modifying the unique field value.
Is this possible in mysql?
EDIT:
Edited after user comment on this post:
You need write table locking on both of those two processes.
A WRITE lock has the following features:
The only session that holds the lock of a table can read and write data from the table.
Other sessions cannot read data from and write data to the table until the WRITE lock is released.
Also look at SQL UNIQUE Constraint
BEFORE EDIT:
Yes it is possible. And it took me awhile to figure it out. I build this on your input and compering values as test1, test2 etc, where test is always the same and has trailing number. As you specified.
It can be done as MySQL TRANSACTION in 4 steps.
Lets say you have table testT where name is unique to insure we have no doubles.
| id | name |
| --- | ----- |
| 1 | test1 |
| 2 | test3 |
And you want to insert a new item with name test1 we set is as:
SET #newName = 'test1';
Then we need to check if it already exists in table:
SELECT #check:=COUNT(*) FROM testT WHERE name = #newName;
We do a count here to get true or false and save it as #check here so we can compare it later. This will result into 1 row as test1 already exists in table.
Next we do another selection to get the highest number of test* and store it as #number, this next query selects all tests and does a SUBSTRING after 4 latter's giving us all numbers after first 4 latter's. (99999999999) numbers actually just to be sure we don't miss any but in our case result is only "3" because that is last record "test3" in table.
SELECT
#number:= SUBSTRING(name,5,99999999999)
FROM testT;
Now we can do an insert:
INSERT INTO testT(name)
VALUES
(
IF(#check = "", #newName , CONCAT(LEFT(#newName,4),RIGHT(#number,1)+1)
)
);
This tries to insert our #newName into table under IF condition, and that is if our #check is empty then he will insert #newName, if not it will take word test out of string and append a highest #number from earlier and add + 1 too it.
So result for #newName = 'test1' is below. If you change this into #newName = 'test3' result wold be same new insert test4.
**Schema (MySQL v5.7)**
SET #newName = 'test1';
---
**Query #1**
SELECT * FROM testT
ORDER BY id;
| id | name |
| --- | ----- |
| 1 | test1 |
| 2 | test3 |
| 3 | test4 |
---
And if you change it in ANY test* that number does not already exists it will insert it normally. In case below: #newName = 'test6'
SET #newName = 'test6';
**Query #1**
SELECT * FROM testT
ORDER BY id;
| id | name |
| --- | ----- |
| 1 | test1 |
| 2 | test3 |
| 3 | test6 |
This way an insert will always be made.
You can play with this here : View on DB Fiddle just by changing SET #newName = 'test6'
I am no expert and it took me couple of hours to figure this way out, as I wanted to know if this was even possible.
And I would appreciate if any other user can suggestion any other way or improve my method.

MYSQL Triggers - how to store the result of a calculated field

I am using MySQL 5.5. I need to add a Trigger to my table using mysql trigger syntax: http://dev.mysql.com/doc/refman/5.0/en/trigger-syntax.html
The example they have given doesn't explain how I can go about doing this -
I have a table - table(a INT, b INT, c INT);. field a and b are numbers, while field c should be a + b. Now i'm sure you are wondering why not just slap this in a view and be done with it, or why not put this in my code. The reason is because I am working with a client that needs the convenience of an auto calc'ed field, with the ability to modify the value incase it needs variation. They are an auditing company and massaging the numbers is often required because of companies missing audit dates etc.
So how can I create a trigger that will:
on insert:
make `c` the value of `a` + `b`.
on update:
if the value of NEW.`c`==OLD.`c` THEN
make `c` the value of `a` + `b`.
ELSE
no change
The reason for the update not changing if the new value is different to the old value is because that would mean they want to modify the number to be slightly different to what the actual sum is.
Please feel free to change my logic - my aim is to preserve the value of c if it has been entered manually and to blast it if it hasn't been touched manually.
Thanks!
I know this is an old question, but if the answer is still needed here it is.
First of all an id column has been added to the table for example's sake to have more direct updates.
CREATE TABLE table1
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
a INT, b INT, c INT
);
Now in INSERT trigger the logic is changed to allow an insert of a pre-calculated value to C column.
CREATE TRIGGER tg_table1_before_insert
BEFORE INSERT ON table1
FOR EACH ROW
SET NEW.c = IF(NEW.c IS NULL, NEW.a + NEW.b, NEW.c);
An update trigger implements the logic per your requirements
CREATE TRIGGER tg_table1_before_update
BEFORE UPDATE ON table1
FOR EACH ROW
SET NEW.c = IF(NEW.c <=> OLD.c, NEW.a + NEW.b, NEW.c);
Now lets do some inserts and updates
INSERT INTO table1 (a, b) VALUES (1, 2), (3, 4);
INSERT INTO table1 (a, b, c) VALUES (5, 6, 0), (7, 8, 100);
UPDATE table1 SET c = 25 WHERE id = 2;
UPDATE table1 SET c = c WHERE id = 3;
As a result we have
| ID | A | B | C |
--------------------
| 1 | 1 | 2 | 3 | -- calculated on insert
| 2 | 3 | 4 | 25 | -- explicitly set on update
| 3 | 5 | 6 | 11 | -- re-calculated on update
| 4 | 7 | 8 | 100 | -- explicitly set on insert
Here is SQLFiddle demo

Need to insert CSV values in MySQL column to another table

I have a CSV file containing user information:
'Arlington', '1,3,5,7,9'
'StackExchange', '2,3'
And I will need the above information imported like this:
"User" table:
id | name
1 | 'Arlington'
2 | 'StackExchange'
"User groups" table:
id | user_id | group_id
1 | 1 | 1
2 | 1 | 3
3 | 1 | 5
4 | 1 | 7
5 | 1 | 9
6 | 2 | 2
7 | 2 | 3
What's the easiest way to do this? I have imported the data with a temp column holding the CSV values:
id | name | tmp_group_ids
1 | 'Arlington' | '1,3,5,7,9'
2 | 'StackExchange' | '2,3'
I am thinking if I import it this way, I will know exactly what id gets assigned for the user (the id column in the users table is auto_increment), and so I can use that id as user_id for the "user groups" table.
But now how do I get values from tmp_group_ids into the "User groups" table?
Would appreciate any help! Thanks!
the easy way would be a php or perl script.
You can use the MySQL SUBSTRING() function to split the string and insert the different values into the table. You can do this by writing a function or using a stored procedure.
I had recently a similar problem, I used the function SUBSTRING_INDEX(str,delim,count), using "," as delimiter
http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_substring-index
INSERT INTO tableUserGroup (userid, groupid)
SELECT
t1.id
, substring_index(t1.tmp_group_ids,',',2)
, substring_index(t1.tmp_group_ids,',',3)
FROM table1 t1
First, insert the names into the User table - with id autonumber, this will work:
INSERT INTO User
(name)
SELECT DISTINCT
name
FROM TempTable
Then:
--- Create a "numbers" table:
CREATE TABLE num
( i INT PRIMARY KEY
) ;
--- Populate it with numbers:
INSERT INTO num
(i)
VALUES
(1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
Then, you can use FIND_IN_SET() function which is handy for this situation (splitting comma-separated fields), like this:
INSERT INTO User_Groups
(user_id, group_id)
SELECT
u.id AS user_id
, num.i AS group_id
FROM User AS u
JOIN TempTable AS t
ON t.name = u.name
JOIN num
ON FIND_IN_SET(num.i, t.tmp_group_ids) > 0