Student Table
id|student_num|name|surname
Course Table
id|course_name
Student_course Table
course_id|student_id|mark
When I insert data into the Student Table (id, student_num, name, surname), the id should be inserted into Student_course Table, student_id column.
Assuming you want to insert the new student for all courses, then in Postgres you can do this:
with new_student as (
insert into student
(id, student_num, name, surname)
values
(1, 42, 'Dent', 'Arthur)
returning id
)
insert into Student_course (student_id, course_id)
select (select id from new_student),
id
from course;
Related
I'm attempting a simple E-R where the two entity sets are : Student & University each having about 200rows & the relationship to be "Applies" [so student applies to university]
I have the student table with a few data but the Primary Key being Student_ID
the University has Univeristy_Name as the PK;
now the relationship - "applies" - I have the student_ID & University_Name as FK & application_ID as PK
I have to populate this "applies" table containing about 10% chosen at random of the possible relationship, using one single INSERT statement & maybe a "random()" function. Does anyone know how do I go about populating the table using values from the other two tables randomly?
You would use:
insert into applies (student_id, university_name)
select s.student_id, u.university_name
from students s cross join
universities u
order by random()
limit 4000;
Alternatively, you can do this without sorting using:
insert into applies (student_id, university_name)
select s.student_id, u.university_name
from students s cross join
universities u
where random() < 0.1;
Note that this is an approximate 10% sample of the rows rather than an exact count.
You can cross join the two tables to get all combinations of student and university. Then number your rows in random order and keep those with a number <= the number of total rows divided by ten to keep 10% of those combinations:
insert into applies (student_id, university_name)
select student_id, university_name
from
(
select
s.student_id,
u.university_name,
row_number() over (order by random()) as rn,
count(*) over () as cnt
from student s
cross join university u
) randomized
where rn <= cnt / 10.0;
I replicated your case with
create table students (student_id serial primary key, name varchar);
create table university (University_Name varchar primary key);
insert into students (name) values ('Francesco');
insert into students (name) values ('Laura');
insert into students (name) values ('Christian');
insert into students (name) values ('Ugo');
insert into students (name) values ('Maria');
insert into students (name) values ('Antonietta');
insert into university values ('Bocconi');
insert into university values ('Universita di Pisa');
insert into university values ('Universita di Padova');
insert into university values ('Universita di Perugia');
If you don't have any limits in students applying for multiple universities, you could achieve the insert with
select * from students cross join university order by random() limit 3;
Where limit 3 displays only 3 rows
I'm using PostgreSQL 12.3.
Similar to the many questions that have been asked about this, like this one, but I need to use data from another table that isn't present in the RETURNING clause.
For a contrived example, consider three tables: customers, products, and sales, and a scenario where a customer needs to be created at the point of sale, and the sales table needs to be updated with both the users and products ids.
CREATE TABLE public.customers (
id SERIAL PRIMARY KEY,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL
)
CREATE TABLE public.products (
id SERIAL PRIMARY KEY,
product TEXT NOT NULL
)
CREATE TABLE public.sales (
id SERIAL PRIMARY KEY,
customer_id INTEGER NOT NULL REFERENCES customers(id),
product_id INTEGER NOT NULL REFERENCES products(id)
)
INSERT INTO customers (first_name, last_name) VALUES ('Bob', 'Smith');
INSERT INTO customers (first_name, last_name) VALUES ('Jane', 'Doe');
INSERT INTO products (product) VALUES ('widget 1');
INSERT INTO products (product) VALUES ('widget 2');
INSERT INTO products (product) VALUES ('widget 3');
INSERT INTO sales (customer_id, product_id) VALUES (1, 1);
INSERT INTO sales (customer_id, product_id) VALUES (2, 1);
INSERT INTO sales (customer_id, product_id) VALUES (2, 2);
If I just need the customer id, the following wouldn't be a problem:
WITH new_customer_and_new_sale AS (
INSERT INTO customers (first_name, last_name) VALUES ('John', 'Doe') RETURNING id
)
INSERT INTO sales (customer_id)
SELECT id FROM new_user_and_new_sale
Since sales has constraints not found in the returning clause, the above obviously won't work. I've tried joining tables to pull in the additional data, but haven't been able to get it to work.
Please overlook any minor issues you may have with the structure of the tables, as the data I'm working with has hundreds of columns and many foreign keys. I've tried to condense the problem into its simplest form, at the risk of seeming contrived.
Your example fails because you're not providing the value for product_id, which is required.
You can directly specify one like this:
WITH inserted_customer AS (
INSERT INTO customers (first_name, last_name) VALUES ('acacaca', 'Doe') RETURNING id
)
INSERT INTO sales (customer_id, product_id)
SELECT inserted_customer.id, 2 FROM inserted_customer;
If you want to get the product ID from an existing product you can do it with a subquery (or a CTE if you're doing more complicated stuff).
WITH inserted_customer AS (
INSERT INTO customers (first_name, last_name) VALUES ('acacaca', 'Doe') RETURNING id
)
INSERT INTO sales (customer_id, product_id)
SELECT inserted_customer.id, (SELECT id FROM products ORDER BY id DESC LIMIT 1) FROM inserted_customer;
If you want to insert the customer and the product on the fly, you can do two CTEs:
WITH inserted_customer AS (
INSERT INTO customers (first_name, last_name) VALUES ('acacaca', 'Doe') RETURNING id
),
inserted_product AS (
INSERT INTO products (product) VALUES ('my product') RETURNING id
)
INSERT INTO sales (customer_id, product_id)
SELECT inserted_customer.id, inserted_product.id
FROM inserted_customer, inserted_product;
Hope this helps!
I want to insert rows in my table like so:
my columns are student,subject,class,teacher,level. Primary key is (student,subject). The table contains all the students, but the Math subject is missing for some of them, so I want to add it without duplicating the ones that already have it.
I've tried this but it gives me unique constraint violated:
insert into table (student,subject,class,teacher,level)
select a.student, 'math', null, null, null
from table a
where a.student in (select distinct student from table where subject not in 'math')
and (a.student,a.subject) not in (select student,subject from table);
I think you basically need select distinct:
insert into table (student, subject)
select distinct a.student, 'math'
from table a
where not exists (select 1
from table a2
where a2.student = a.student and
a2.subject = 'math'
);
One approach would be to use minus:
insert into course_students (student, subject)
select student, 'Math' from course_students
minus
select student, subject from course_students;
This would would need extending a little if you wanted to include other columns in the insert:
insert into course_students (student, subject, class, teacher, course_level)
select student, subject, '101', 'Naomi', 1
from ( select student, 'Math' as subject from course_students
minus
select student, subject from course_students );
I am trying to find student who has min score which will be the result of the below query. However, I was asked to write the query without using MIN(). Spent several hours but I can't find the alternative solution :'(.
select s.sname
from student s
where s.score =
(select min(s2.score)
from score s2)
This is one way, which will work even if two students have same lowest score.
SELECT distinct s1.sname
FROM student s1
LEFT JOIN student s2
ON s2.score < s1.score
WHERE s2.score IS NULL
The below is the method using limit, which will return lowest score student, but only one of them if multiple of them have same score.
select sname
from student
order by score asc
limit 1
Here's a possible alternative to the JOIN approach:
select sname from student where score in
(select score from student order by score asc limit 1)
create table student (name varchar(10), score int);
insert into student (name, score) values('joe', 30);
insert into student (name, score) values('jim', 88);
insert into student (name, score) values('jack', 22);
insert into student (name, score) values('jimbo', 15);
insert into student (name, score) values('jo bob',15);
/* folks with lowest score */
select name, score from student where not exists(select 1 from student s where s.score < student.score);
/* the actual lowest score */
select distinct score from student
where not exists(select 1 from student s where s.score < student.score);
Note that not exists can be brutally inefficient, but it'll do the job on a small set.
One way of doing it would be to Order the results in Ascending order and take the first row.
But if you are looking at a more generic solution as a student will have more than one mark associated with him, So you need to find the total marks for each student and then find the student with the least total.
This is the first scenario, A student only has one row in the table.
CREATE TABLE Student
(
SLNO INT,
MARKS FLOAT,
NAME NVARCHAR(MAX)
)
INSERT INTO Student VALUES(1, 80, 't1')
INSERT INTO Student VALUES(2, 90, 't2')
INSERT INTO Student VALUES(3, 76, 't3')
INSERT INTO Student VALUES(4, 98, 't4')
INSERT INTO Student VALUES(5, 55, 't5')
SELECT * From Student ORDER BY MARKS ASC
The second scenario as specified above is, He has multiple rows in the table, So we insert two more rows into the table for existing users.
Then we select the users by taking the sum of their marks grouping the results by name and then ordering the results by their total
INSERT INTO Student VALUES(6, 55, 't1')
INSERT INTO Student VALUES(6, 90, 't5')
SELECT SUM(MARKS) AS TOTAL, NAME FROM Student
GROUP BY NAME
ORDER BY TOTAL
Hope the above is what you are looking for.
You can try stored procedure to find student with minimum score.
I have a table "User" (idUser, name, departmentId) and another table "Department" (idDepartment, name).
I would like to insert random data into table User, but it would be necessary to consider only the departments previously inserted.
I think it would be something like:
INSERT INTO User (idUser, name, departmentId)
VALUES (seq_user.nextVal, 'random name', FK_RANDOM_DEPARTMENT);
How can I generate this 'random name' and only use departments that I have already inserted?
Thanks in advance!
INSERT INTO User
(idUser, name, departmentId)
VALUES
(seq_user.nextVal,
DBMS_RANDOM.STRING('L', 20), /*20 is a number of characters in a string*/
(SELECT * FROM (SELECT idDepartment FROM Department ORDER BY DBMS_RANDOM.VALUE) WHERE ROWNUM = 1)
);