I have 3 Mysql tables.
A table with the classes and the labs and their id.
A table with the teachers_list and their subject.
A table which is going to be the schedule.**
I want to randomly assign one of the physicists to one of the physics labs on my third table which is going to be the schedule.
INSERT INTO schedule(teacher_name, class_id)
VALUES (select teacher_name from teachers_list where subject="Physicist” order by rand() limit 1,
select id from lab_list where lab="Physics_lab" order by rand() limit 1);
**This one doesn't work :(
Can you help me?**
I think that you want the insert ... select syntax, along with a subquery:
insert into schedule(teacher_name, class_id)
select
(
select teacher_name
from teachers_list
where subject = 'Physicist'
order by rand()
limit 1
),
id
from lab_list
where lab = 'Physics_lab'
Related
original question:
Your University has three courses. Information about the students in these courses is stored in the mysql_students, postgresql_students and java_students tables.
The tables are already created with the following schema and required data :
id INT Primary key
name VARCHAR(100)
score INT
Write an SQL statement to find the names of top 5 students in each course. Resulting table should have one column names. The names of the student from each course should be in order by mysql_students, postgresql_students and java_students. The names of student who has same course should be sorted in ascending order.
Given data:
CREATE TABLE mysql_students(
id INT Primary key,
name VARCHAR(100),
score INT
);
CREATE TABLE postgresql_students(
id INT Primary key,
name VARCHAR(100),
score INT
);
CREATE TABLE java_students (
id INT Primary key,
name VARCHAR(100),
score INT
);
INSERT INTO mysql_students VALUES(1,'Maria Anders',750);
INSERT INTO mysql_students VALUES(2,'Ana Trujillo',890);
INSERT INTO mysql_students VALUES(3,'Antonio Moreno',400);
INSERT INTO mysql_students VALUES(4,'Thomas Hardy',910);
INSERT INTO mysql_students VALUES(5,'Christina',600);
INSERT INTO mysql_students VALUES(6,'Hanna',120);
INSERT INTO mysql_students VALUES(7,'Frederique',891);
INSERT INTO mysql_students VALUES(8,'Martin Sommer',490);
INSERT INTO mysql_students VALUES(9,'Laurence',790);
INSERT INTO mysql_students VALUES(10,'Elizabeth',690);
INSERT INTO postgresql_students VALUES(1,'Victoria',750);
INSERT INTO postgresql_students VALUES(2,'Patricio',800);
INSERT INTO postgresql_students VALUES(3,'Francisco',400);
INSERT INTO postgresql_students VALUES(4,'Yang',960);
INSERT INTO postgresql_students VALUES(5,'Christina',675);
INSERT INTO java_students VALUES(1,'Pedro',350);
INSERT INTO java_students VALUES(2,'Elizabeth',490);
INSERT INTO java_students VALUES(3,'Francisco',400);
INSERT INTO java_students VALUES(4,'Sven',510);
INSERT INTO java_students VALUES(5,'Janine',600);
INSERT INTO java_students VALUES(6,'Hanna',120);
INSERT INTO java_students VALUES(7,'Frederique',891);
The expected output:
names
Ana Trujillo
Frederique
Laurence
Maria Anders
Thomas Hardy
Christina
Francisco
Patricio
Victoria
Yang
Elizabeth
Francisco
Frederique
Janine
Sven
Please keep in mind I am a beginner.
Now, I tried using union and it almost works, the issue being that it sorts the scores-- but doesn't sort the names alphabetically w.r.t their course after it fetches the records from the tables, and I am not sure how to do it. This is what I have so far:
db<>fiddle here
SELECT *
FROM (
(SELECT name 'names'
FROM mysql_students
ORDER BY score DESC
LIMIT 5)
UNION
(SELECT name 'names'
FROM postgresql_students
ORDER BY score DESC
LIMIT 5)
UNION
(SELECT name 'names'
FROM java_students
ORDER BY score DESC
LIMIT 5))
ORDER BY NAMES
Actual Results:
names
Ana Trujillo
Christina
Elizabeth
Francisco
Frederique
Janine
Laurence
Maria Anders
Patricio
Sven
Thomas Hardy
Victoria
Yang
It is very likely that my approach itself is wrong-- I have been brainstorming for hours and I cannot think of how to do this. Please help. Guidance is greatly appreciated.
I found a solution!!!
Select name as 'names'
from
(
(Select name, 1 as filter from mysql_students order by score desc limit 5)
Union all
(Select name, 2 as filter from postgresql_students order by score desc limit 5)
union all
(Select name, 3 as filter from java_students order by score desc limit 5)
)
as w
order by filter, names;
I looked up how to combine tables with UNION without changing the order of the records from individual tables. So, first I selected the top 5 students from each table, assigned the same number to each record per different table. Then I UNION'd them. This way, even if they get jumbled after UNION, they can be reordered in accordance to the table they belonged to using filter. So in the last line, the ORDER BY prioritizes filter, then name (now called names).
in fact your code tell database to select the data and then sort all first student by name but the in assignment they want you to sort only the first five student by their name this is the mistake you can try use this code i think it work
select
*
from
(
select
*
from
mysql_students
order by score desc
limit 5
) as t
order by name;
select
*
from
(
select
*
from
postgresql_students
order by score desc
limit 5
) as t
order by name;
select
*
from
(
select
*
from
java_students
order by score desc
limit 5
) as t
order by name;
I have a table with a limit of 3 rows per user, so each user can only add 3 elements in the table.
I wrote something like:
INSERT INTO 'MyTable' ('ID', 'eMail', 'ISBN')
VALUES ('333', 'a#d', '222') , ('433','e#r', '223')
but the problem is that I have no idea how to set the limit for the insertion. I just know that I cannot use LIMIT because it only works with a SELECT query.
I don't know is there any single query that will handle limit and insert at once or not? I would rather count rows by each user id before inserting new rows for that user.
For Example:
SELECT ID, COUNT(*) as CNT from `MyTable` GROUP BY ID HAVING COUNT(*) < 3 ORDER BY `ID` DESC
So the above query will return only the ID->respective row count of that ID, with this information you can easily filter out which user can have new row on your table and which should be discarded?
ID CNT
333 2
899 1
443 2
INSERT INTO 'MyTable' ('ID', 'eMail', 'ISBN') VALUES ('333', 'a#d', '222') , ('899','e#r', '223'), ('443','f#r', '224')
My table has a TIME field.
I want to keep only 5 newest rows.
Can I delete the old rows without using SELECT?
I think logic should be something like this:
DELETE FROM tbl WHERE row_num > 5 ORDER BY TIME
How can I implement this in MySQL whitout using SELECT to get list of TIME values?
Without proper ORDER BY clause, SQL result set have to be considered as unordered.
You have to provide a column to explicitly store your rows sequence numbers. This could be a time stamp or the auto_increment column of your table.
Please keep in mind you could have concurrent access to your table as well. What should be the expected behavior if someone else is inserting while you are deleting? As far as I can tell this could lead to situation where you keep only the "5 latest rows" + "those inserted on the other transaction".
If your have the time column for that purpose on your table and a PRIMARY KEY (or some other UNIQUE NOT NULL column) you could write:
DELETE tbl FROM tbl LEFT JOIN (SELECT * FROM tbl ORDER BY tm DESC LIMIT 5) AS k
ON (tbl.pk) = (k.pk)
WHERE k.`time` IS NULL;
If you have composite primary key (a,b) You could write:
DELETE tbl FROM tbl LEFT JOIN (SELECT * FROM tbl ORDER BY tm DESC LIMIT 5) AS k
ON (tbl.a,tbl.b) = (k.a,k.b)
WHERE k.tm IS NULL;
DELETE FROM TBL
WHERE ROW_NUM = (SELECT ROW_NUM FROM TBL LIMIT 6, 99999)
ORDER BY TIME DESC;
This will delete records from 6, 7, 8, 9, 10, ....., 200005
Because LIMIT range starts here from 6 to 9999 records, means 200005
Maybe this would be an alternative:
DELETE FROM tbl
WHERE primary_key NOT IN (SELECT primary_key
FROM tbl
ORDER BY time
DESC LIMIT 5)
If you want to exclude the top 5 rows, use something like:
DELETE FROM table WHERE primary_key IN
(SELECT primary_key FROM table LIMIT 1 OFFSET 5,1000000)
100000 can be a very large no
I have a table with 3 columns: id, date and name. What I am looking for is to delete the records that have a duplicate name. The rule should be to keep the record that has the oldest date. For instance in the example below, there is 3 records with the name Paul. So I would like to keep the one that has the oldest date (id=1) and remove all the others (id = 4 and 6). I know how to make insert, update, etc queries, but here I do not see how to make the trick work.
id, date, name
1, 2012-03-10, Paul
2, 2012-03-10, James
4, 2012-03-12, Paul
5, 2012-03-11, Ricardo
6, 2012-03-13, Paul
mysql_query(?);
The best suggestion I can give you is create a unique index on name and avoid all the trouble.
Follow the steps as Peter Kiss said from 2 to 3. Then do this
ALTER Table tablename ADD UNIQUE INDEX name (name)
Then Follow 4 Insert everything from the temporary table to the original.
All the new duplicate rows, will be omitted
Select all the records what you want to keep
Insert them to a temporary table
Delete everything from the original table
Insert everything from the temporary table to the original
Like Matt, but without the join:
DELETE FROM `table` WHERE `id` NOT IN (
SELECT `id` FROM (
SELECT `id` FROM `table` GROUP BY `name` ORDER BY `date`
) as A
)
Without the first SELECT you will get "You can't specify target table 'table' for update in FROM clause"
Something like this would work:
DELETE FROM tablename WHERE id NOT IN (
SELECT tablename.id FROM (
SELECT MIN(date) as dateCol, name FROM tablename GROUP BY name /*select the minimum date and name, for each name*/
) as MyInnerQuery
INNER JOIN tablename on MyInnerQuery.dateCol = tablename.date
and MyInnerQuery.name = tablename.name /*select the id joined on the minimum date and the name*/
) /*Delete everything which isn't in the list of ids which are the minimum date fore each name*/
DELETE t
FROM tableX AS t
LEFT JOIN
( SELECT name
, MIN(date) AS first_date
FROM tableX
GROUP BY name
) AS grp
ON grp.name = t.name
AND grp.first_date = t.date
WHERE
grp.name IS NULL
DELETE FROM thetable tt
WHERE EXISTS (
SELECT *
FROM thetable tx
WHERE tx.thename = tt.thename
AND tx.thedate > tt. thedate
);
(note that "date" is a reserver word (type) in SQL, "and" name is a reserved word in some SQL implementations)
SELECT id FROM table LIMIT 8, 3
results in 8,9,10
but I need 10,9,8
How can you do this? If you add "ORDER BY id DESC" it gets 3,2,1
Put your query in a subselect and then reverse the order in the outer select:
SELECT id from (
SELECT id FROM table ORDER BY id LIMIT 8, 3
) AS T1 ORDER BY id DESC
Test data:
CREATE TABLE table1 (id INT NOT NULL);
INSERT INTO table1 (id) VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11);
SELECT id from (
SELECT id FROM table1 ORDER BY id LIMIT 8, 3
) AS T1 ORDER BY id DESC
Result:
10
9
8
Note that the ORDER BY in the subquery is required otherwise the order is undefined. Thanks to Lasse for pointing this out!
First of all, if you're not ordering at all, that you got 8,9,10 right now might be related to the index used. Are you sure this isn't going to change in the future?
What I'm getting at is that unless you specify an order, you should not rely on it being the one you want.
So I would definitely add an order to that select to specify what you want. Otherwise you're only saying "give me 3 numbers from this table", not "give me 3 numbers from this table according to these rules". Why is 3,2,1 wrong but 8,9,10 right? You're not specifying.
Anyway, to answer your question, you must order after the limit, which means a subselect:
SELECT id FROM (
SELECT id FROM table LIMIT 8, 3
) AS dummy ORDER BY id DESC
However, I would try this SQL instead, related to the part about specifying:
SELECT id FROM (
SELECT id FROM table ORDER BY id LIMIT 8, 3
) AS dummy ORDER BY id DESC