Insert or update with select and override nulls - sql

I got two tables: defaults and users with same columns, except in defaults the column user_id is unique while in "users" it's not.
I want to take all the rows from users and insert them to defaults, if two rows in users got the same user_id, I want to merge them in such way that all the empty/null values will be overridden with non empty/null values
Here is an example
users
-----
user_id|name|email|address
--------------------------
1 |abc |null |J St
1 |coco|a#b.c|null
After inserting to defaults I expect the next result:
defaults
-----
user_id|name|email|address
--------------------------
1 |abc |a#b.c|J St
#Eric B provided an answer of how to do this with insert values:
Assuming 3 columns in the table.. ID, NAME, ROLE
This will update 2 of
the columns. When ID=1 exists, the ROLE will be unaffected. When ID=1
does not exist, the role will be set to 'Benchwarmer' instead of the
default value.
INSERT OR REPLACE INTO Employee (id, name, role)
VALUES ( 1,
'Susan Bar',
COALESCE((SELECT role FROM Employee WHERE id = 1), 'Benchwarmer')
);
How to do this when I use select for my insert
insert or replace into defaults select ??? from users

INSERT OR REPLACE INT DEFAULTS VALUES (ID, Name, Role)
(
SELECT ID, MAX(Name), MAX(Role) FROM Users GROUP BY ID
);
The max will select the max value instead of null if there is one.

Related

show the affected rows after update/insert/delete in DB2

hello I used to work with Postgres and there if I want to see the affected rows after a manipulation I used the key word RETURNING
Example to show all the columns of the affected row(s):
UPDATE tblName
SET colName='something'
WHERE colName='something'
RETURNING *;
can anyone tell me how I do the same thing with DB2 ?
Example for DB2:
CREATE TABLE MYTABLE (
ID INTEGER GENERATED ALWAYS AS IDENTITY,
NAME CHAR(30),
AGE SMALLINT,
)
SELECT ID, NAME, AGE
FROM FINAL TABLE
(
INSERT INTO MYTABLE (NAME, AGE)
VALUES('Jon Smith', 35)
)
Result:
ID NAME AGE
1 Jon Smith 35

Adding a LEFT JOIN on a INSERT INTO....RETURNING

My query Inserts a value and returns the new row inserted
INSERT INTO
event_comments(date_posted, e_id, created_by, parent_id, body, num_likes, thread_id)
VALUES(1575770277, 1, '9e028aaa-d265-4e27-9528-30858ed8c13d', 9, 'December 7th', 0, 'zRfs2I')
RETURNING comment_id, date_posted, e_id, created_by, parent_id, body, num_likes, thread_id
I want to join the created_by with the user_id from my user's table.
SELECT * from users WHERE user_id = created_by
Is it possible to join that new returning row with another table row?
Consider using a WITH structure to pass the data from the insert to a query that can then be joined.
Example:
-- Setup some initial tables
create table colors (
id SERIAL primary key,
color VARCHAR UNIQUE
);
create table animals (
id SERIAL primary key,
a_id INTEGER references colors(id),
animal VARCHAR UNIQUE
);
-- provide some initial data in colors
insert into colors (color) values ('red'), ('green'), ('blue');
-- Store returned data in inserted_animal for use in next query
with inserted_animal as (
-- Insert a new record into animals
insert into animals (a_id, animal) values (3, 'fish') returning *
) select * from inserted_animal
left join colors on inserted_animal.a_id = colors.id;
-- Output
-- id | a_id | animal | id | color
-- 1 | 3 | fish | 3 | blue
Explanation:
A WITH query allows a record returned from an initial query, including data returned from a RETURNING clause, which is stored in a temporary table that can be accessed in the expression that follows it to continue work on it, including using a JOIN expression.
You were right, I misunderstood
This should do it:
DECLARE mycreated_by event_comments.created_by%TYPE;
INSERT INTO
event_comments(date_posted, e_id, created_by, parent_id, body, num_likes, thread_id)
VALUES(1575770277, 1, '9e028aaa-d265-4e27-9528-30858ed8c13d', 9, 'December 7th', 0, 'zRfs2I')
RETURNING created_by into mycreated_by
SELECT * from users WHERE user_id = mycreated_by

Need SQL command that will insert a row after specific row

I need SQL command that will insert a row after specific row.
Example:-
Before table
Id. Name.
1. Xyz.
2. Xyz
3. Xyz
Want result need to add 'Abc' data after each 'xyz' having same id like:-
Id. Name.
1. Xyz.
1. Abc
2. Xyz
2. Abc
3. Xyz
3. Abc
You need UNION ALL:
SELECT t.*
FROM (SELECT id, Name
FROM table t
UNION ALL
SELECT ID, 'Abc'
FROM table t
) t
ORDER BY ID, NAME;
This will not insert row, it just provide you run time view. If you want only insert then you need to truncate your table (note : take a backup of current table ) & perform insert operation.
INSERT INTO your_table
SELECT Id
,'Abc' AS Name
FROM your_table
Where Name = 'Xyz'
I am not sure if OVERRIDING SYSTEM VALUE is needed, it depends on your table. But this query should do what you need. It will get all the rows that contain the Xyz value and use the same id and a different name. Then if you order by Id because remember ordering is never guaranteed if you don't use order by
Try this
START TRANSACTION;
UPDATE table_sample SET column = column+1 WHERE column >= some_value_here ";
INSERT INTO table_sample (id, column_name) VALUES
(NULL, 'value_here');
COMMIT;

Replacing values with random values from other table. Oracle

I want to update names in a table with random names from another table. There's real user names in the table Users. There's made up names in the table tmp_users. I'd like to update all the names in Users table with random names from the tmp_users table. The idea is to anonymize real production data with fake customers. There are fewer entries in the tmp_users table so I don't think I can correlate on an id.
The problem I have is that all users gets set to the same name.
Some sample data:
create table users
(
name varchar2(50)
);
create table tmp_users
(
name varchar2(50)
);
insert into users values ('Cora');
insert into users values ('Rayna');
insert into users values ('Heidi');
insert into users values ('Gilda');
insert into users values ('Dorothy');
insert into users values ('Elena');
insert into users values ('Providencia');
insert into users values ('Louetta');
insert into users values ('Portia');
insert into users values ('Rodrick');
insert into users values ('Rocco');
insert into users values ('Nelson');
insert into users values ('Derrick');
insert into users values ('Everett');
insert into users values ('Nisha');
insert into users values ('Amy');
insert into users values ('Hyun');
insert into users values ('Brendon');
insert into users values ('Gabriela');
insert into users values ('Melina');
insert into tmp_users values ('Snow White');
insert into tmp_users values ('Cinderella');
insert into tmp_users values ('Aurora');
insert into tmp_users values ('Ariel');
insert into tmp_users values ('Belle');
insert into tmp_users values ('Jasmine');
insert into tmp_users values ('Pocahontas');
insert into tmp_users values ('Mulan');
insert into tmp_users values ('Tinker Bell');
insert into tmp_users values ('Anna');
insert into tmp_users values ('Elsa');
--Wrong, sets all users to the same random name
update users set name = (select name from (select name from tmp_users order by sys_guid()) where rownum = 1);
--Wrong, sets all users to the same random name
update users set name = (select name from (select name from tmp_users order by dbms_random.value) where rownum = 1);
When doing this:
select * from users;
The result I get is something like this, which I don't want.
Cinderella
Cinderella
Cinderella
Cinderella
Cinderella
...
I'd like to assign a random name to each row in the Users table. Not the same name to all rows. I'd like somthing like this:
Mulan
Cinderella
Belle
Elsa
Jasmine
Tinker Bell
...
Any idea how this can be done? I'm using Oracle Database 11g Express Edition 11.2.0.2.0. It would be easy to do with a cursor but I'm trying to figure out how to do it with a set operation.
Update:
I've now tested on two different Oracle versions. The correlated subquery solution doesn't work on Oracle Database 11g Express Edition 11.2.0.2.0.
But it does work sometimes on Oracle Database 11g Enterprise Edition 11.2.0.4.0. On one table it works all the time and on another it never works.
Testing with 11.2.0.4 the following works, similar to what #VR46 suggested:
SQL> UPDATE users u
2 SET name = (SELECT name
3 FROM (SELECT NAME,
4 row_number() over(ORDER BY dbms_random.value) rn
5 FROM tmp_users) tu
6 WHERE u.name IS NOT NULL
7 AND rn = 1);
20 rows updated
SQL> select * from users;
NAME
--------------------------------------------------
Ariel
Aurora
Belle
Ariel
Anna
Mulan
Aurora
Ariel
Mulan
Tinker Bell
Mulan
Ariel
Aurora
Pocahontas
Pocahontas
Aurora
Snow White
Mulan
Aurora
Anna
20 rows selected
I think correlating the sub-query will pull random names from Sub-Query
UPDATE users
SET name = (SELECT name
FROM (SELECT name
FROM tmp_users tu
ORDER BY Sys_guid())
WHERE ROWNUM = 1
AND users.name <> name );
You need some correlation, as #VR46 suggested; but sys_guid() doesn't work for this (in 11gR2 anyway; I think the optimiser is only evaluating it once in this scenario for some reason, perhaps); you can use dbms_random.value though:
update users u set name = (
select name from (
select name from tmp_users order by dbms_random.value
)
where rownum = 1 and u.name is not null
);
NAME
--------------------------------------------------
Jasmine
Tinker Bell
Ariel
Elsa
Elsa
Elsa
Belle
Snow White
...
If you don't want aubquery you could use keep dense rank instead:
update users u set name = (
select max(name) keep (dense_rank first order by dbms_random.value)
from tmp_users
where u.name is not null
);
NAME
--------------------------------------------------
Mulan
Anna
Snow White
Elsa
Tinker Bell
Belle
Belle
Elsa
...
The correlation just has to be true; if you have null values in your user table this will update them to null, and you could use a different condition if that is an issue.
From comments it seems you have the same problem with dbms_random in 11.2.0.2 as I have with sys_guid in 11.2.0.3 and 11.2.0.4. If your users table also has a numeric unique/primary key such as an ID you can use that for the correlation and pass it into the value function, which might make a difference, but I don't have a suitable instance to test against:
update users u set name = (
select max(name) keep (dense_rank first order by dbms_random.value(0, u.id))
from tmp_users
);
MOS note 420779.1 includes the line "Including DBMS_RANDOM.VALUE in a subquery may or may not work depending on the optimization and execution code path chosen", which seems to be the problem here.
You could also try variations with merge, e.g. (again assuming there's an ID you can use):
merge into users u
using (
select u.id, max(tu.name) keep (dense_rank first
order by dbms_random.value(0, u.id)) as name
from users u
cross join tmp_users tu
group by u.id
) tu
on (tu.id = u.id)
when matched then update set u.name = tu.name;
The cross join may make this impractical though, depending on the number of rows you actually have in each table.
Here's one more approach, which uses rowid and modulus:
MERGE into users_tab u
USING (
select
actual.row_id as actual_rowid,
actual.rnum actual_rnum,
actual.name actual_name,
fake.rnum fake_rnum,
fake.name fake_name,
mod(actual.rnum, fake_count.cnt) modulus
from
(
select rownum rnum, name, rowid as row_id
from users_tab
) actual,
(
select rownum-1 rnum, name
from (select distinct name from tmp_users_tab)
) fake,
(select count(distinct name) cnt from tmp_users_tab) fake_count
where mod(actual.rnum, fake_count.cnt) = fake.rnum
) x
ON (x.actual_rowid = u.rowid)
WHEN MATCHED THEN UPDATE
set name = x.fake_name;
Not sure about how this will perform on a very large user table, however. Its not random, but follows a series of fake names. So if you have 10 fake names, records 1->10 in users will be assigned fake names 1->10, and user 11 will start over with fake name #1.
The USING query has extra fields for testing.

Insert query issue- with foreign key

I am new to SQL. Need a help from you guys :)
I am building a java appl and stuck in one of the scenario for insert with foreign key. Suppose I have 2 tables Employee_Type and Employee:
Table Employee_Type
| idType | position |
| -------- | -------------- |
| 1| Manager|
Table Employee
empId
EmpName
emp_type
FK (emp_type) reference Employee_type(idType)
Now values in Employee_Type
1,
Manager
I am inserting manually into Employee Table
INSERT INTO
employee (empId, name, emp_type)
VALUES
(
10, 'prashant', 1
)
Here in above insert I am inserting manually emp_type which is FK . My question, is there any way to insert FK value automatically using select like below example?
INSERT INTO
employee(empId, name, emp_type)
VALUES
(
10, 'prashant',
(
SELECT
idType
FROM
Employee_type,
employee
WHERE
employee.emp_type = employee_type.idtype
)
)
You don't specify your RDBMS and the syntax may therefore differ, but you should be able to restructure the statement to use literal values in an INSERT INTO ... SELECT format:
INSERT INTO employee (empId,name,emp_type)
SELECT
/* Build a SELECT statement which includes the static values as literals */
'10' AS empId,
'prashant' AS name,
/* and the idType column */
idType
FROM Employee_type,employee
WHERE employee.emp_type=employee_type.idtype
Note that without anything else in the WHERE clause, the above will insert one row into employee for every row matched by the SELECT statement.