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

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

Related

How is the below query evaluated by the complier?

I was trying to create alternate queries to get the required result just came up with the below code. The below code gives Robert as the result i want to understand how is the compiler evaluated the below code.
CREATE TABLE NAMES(Id integer PRIMARY KEY, Name text);
/* Create few records in this table */
INSERT INTO NAMES VALUES(1,'Tom');
INSERT INTO NAMES VALUES(2,'Lucy');
INSERT INTO NAMES VALUES(3,'Frank');
INSERT INTO NAMES VALUES(4,'Jane');
INSERT INTO NAMES VALUES(5,'Robert');
COMMIT;
/* Display all the records from the table */
SELECT * FROM NAMES a where 0 = (select count(Name) from NAMES b where b.Id > a.Id);
For each row in names it is checked whether the number of rows with a higher ID is 0. Only in that case is the row selected. This means only the row with the highest ID gets selected.
It is unnecessary to count, though. More typical would be a NOT EXISTS query:
SELECT *
FROM names
WHERE NOT EXISTS
(
SELECT NULL
FROM names name_with_higher_id
WHERE name_with_higher_id.id > names.id
);
Or a MAX query:
SELECT *
FROM names
WHERE id = (SELECT max(id) FROM names);

Simple select query missing rows in Ignite

Selecting by ID over a table with 2 entries results in a single output result.
Here's the example table:
CREATE TABLE IF NOT EXISTS Person(
id int,
city_id int,
name varchar,
age int,
company varchar,
PRIMARY KEY (id, city_id)
);
INSERT INTO Person (id, name, city_id) VALUES (1, 'John Doe', 3);
INSERT INTO Person (id, name, city_id) VALUES (1, 'John Dean', 4);
The following queries were executed in the same order:
"SELECT * FROM Person" returns both rows - expected
"SELECT * FROM Person WHERE age is null" returns both rows - expected
"SELECT * FROM Person WHERE id = 1" returns only the first row, when it was expected to return both rows.
Would you be able to help me understand what is going on here?
Thanks!
Edit
This is an active critical issue being tracked here: https://issues.apache.org/jira/browse/IGNITE-12068
The issue has been fixed by the community and will be available in the upcoming release shortly:
https://issues.apache.org/jira/browse/IGNITE-12068
Thanks for reporting.

Insert or update with select and override nulls

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.

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.