Insert query issue- with foreign key - sql

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.

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

Postgresql insert if does not exist

I have the following query
INSERT INTO address (house_number, street, city_id)
values(11, 'test st', (select id from city where LOWER(city) = LOWER('somecity')))
Is there anyway to insert "somecity" in the city table if "somecity" does not exist in city then after inserting, it would return the ID for the inserted row?
I did find this answer that says upsert can be used to achieve this
https://stackoverflow.com/a/31742830/492015
but I can't find an example that inserts if select does not return the row.
Instead of nesting the INSERTs, you could use a CTE
to perform the INSERTs one after the other but as a single statement:
WITH tmp AS (
INSERT INTO test_city (city) VALUES ('somecity')
ON CONFLICT (lower(city)) DO UPDATE SET city = excluded.city
RETURNING id, city
)
INSERT INTO test_address (house_number, street, city_id)
SELECT house_number, street, id
FROM (VALUES (11, 'test st', 'somecity')) val (house_number, street, city)
LEFT JOIN tmp USING (city)
RETURNING *
Using this setup:
DROP TABLE IF EXISTS test_address;
DROP TABLE IF EXISTS test_city;
CREATE TABLE test_address (
house_number int
, street text
, city_id int
);
CREATE TABLE test_city (
id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
, city text
);
CREATE UNIQUE INDEX test_city_uniq_idx ON test_city USING btree (lower(city));
INSERT INTO test_city (city) VALUES ('Somecity');
and with the INSERT above, the query
SELECT * FROM test_address;
yields
| house_number | street | city_id |
|--------------+---------+---------|
| 11 | test st | 1 |
and
SELECT * FROM test_city;
yields
| id | city |
|----+----------|
| 1 | somecity |
Note that the CTE replaces
(select id from city where LOWER(city) = LOWER('somecity'))
with an INSERT .. ON CONFLICT .. DO UPDATE statement:
INSERT INTO test_city (city) VALUES ('somecity')
ON CONFLICT (lower(city)) DO UPDATE SET city = excluded.city
RETURNING id, city
I used DO UPDATE instead of DO NOTHING so that RETURNING id, city will always return something. If you use DO NOTHING, then nothing is returned when there is a conflict.
Note however that a consequence of using city = excluded.city is that the original 'Somecity'
gets replaced by 'somecity'. I'm not sure you'll find that behavior acceptable, but unfortunately I haven't figured out how to do nothing when there is a conflict and yet return id and city at the same time.
Another issue you may have with the above solution is that I used a unique index on lower(city):
CREATE UNIQUE INDEX test_city_uniq_idx ON test_city USING btree (lower(city));
This allows you to use the identical condition in the INSERT statement:
INSERT ... ON CONFLICT (lower(city))
as a substitute for the condition LOWER(city) = LOWER('somecity') which appeared in your SELECT statement. It produces the desired effect, but the trade-off is that now you have a unique index
on (lower(city)).
Regarding the followup question
of how to insert into more than 2 tables:
You can chain together more than one CTE, and the subsequent CTEs can even reference the prior CTEs. For example,
CREATE UNIQUE INDEX city_uniq_idx ON city USING btree (lower(city));
CREATE UNIQUE INDEX state_uniq_idx ON state USING btree (lower(state_code));
WITH tmpcity AS
(
INSERT INTO
city (city)
VALUES
(
'Miami'
)
ON CONFLICT (lower(city)) DO
UPDATE
SET
city = excluded.city RETURNING id, city
)
, tmpstate as
(
INSERT INTO
state (state_code)
VALUES
(
'FL'
)
ON CONFLICT (lower(state_code)) DO
UPDATE
SET
state_code = excluded.state_code RETURNING id, state_code
)
INSERT INTO
address (house_number, street, city_id, state_id)
SELECT
house_number,
street,
tmpcity.id,
tmpstate.id
FROM
(
VALUES
(
12,
'fake st.',
'Miami',
'FL'
)
)
val (house_number, street, city, state_code)
LEFT JOIN
tmpcity USING (city)
LEFT JOIN
tmpstate USING (state_code)
ON CONFLICT (street) DO NOTHING

SQL split column

I made an easy exemple to understand better what is my question.
So, i have 2 table and i have a selection based on inner join which is into a selection.
create table students(
id_student number,
name_student varchar2(15),
id_advisor number,
money number
);
insert into students values(1, 'Student_1', 1, 100);
insert into students values(2, 'Student_2', 8,-200);
insert into students values(4, 'Student_4', 7, 256);
insert into students values(5, 'Student_5', 3, -305);
----------------
create table advisors(
id_advisor number,
name_advisor varchar2(15)
);
insert into advisors values(1, 'advisor_1');
insert into advisors values(3, 'advisor_3');
insert into advisors values(5, 'advisor_5');
------------------------------------------
SELECT name_advisor, money as money_pozitive
FROM(
select name_student, name_advisor, money from students
inner join advisors on students.id_advisor = advisors.id_advisor)
WHERE money > 0
With this code i have the following result:
name_advisor | money_pozitive
------------------------------------
advisor_1 | 100
My question is, how I add an extra column named money_negative with of course negative values ? like this:
name_advisor | money_pozitive | money_negative
---------------------------------------------------------
advisor_1 | 100 | -305
Just use case:
select name_student, name_advisor,
(case when money > 0 then money end) as money_positive,
(case when money < 0 then money end) as money_negative
from students s inner join
advisors a
on s.id_advisor = a.id_advisor;
Notes:
A subquery is not necessary.
Use table aliases. These make a query easier to write and to read.
If you have multiple table names, it is a good habit to qualify all column names (i.e., use the table aliases for the column names).
And you don't need a where clause.

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.