How to insert many rows into two relative tables in mysql? - mysql

I want to insert many rows into two relative tables. I used LAST_INSERTED_ID() to insert data into the second table, but this id does not change
BEGIN;
insert into themes (tutorID, year, theme_name, degreeID)
select tutorID, year, work_name, degreeID from journal;
INSERT INTO assigned_students (studentID, tutorID, themeID, writing_language_id, work_typeID)
select studentID, tutorID, LAST_INSERT_ID(), 0, 4 from journal;
COMMIT

Give this a try, where you declare a INT and then set that value, see below.
BEGIN;
declare lastid INT;
insert into table1 (tutorID, year, name, degreeID)
select sm.tutorID, year, namework, dt.degreeID from table3;
set lastid = (SELECT LAST_INSERT_ID());
INSERT INTO table2 (studentID, tutorID, table1ID, writing_language_id, work_typeID)
select distinct StudentID, tutorID, lastid , 0, 4 from table3;
COMMIT;
You can also try this.
BEGIN;
insert into table1 (tutorID, year, name, degreeID)
select sm.tutorID, year, namework, dt.degreeID from table3;
INSERT INTO table2 (studentID, tutorID, table1ID, writing_language_id, work_typeID)
select distinct StudentID, tutorID, (SELECT LAST_INSERT_ID()), 0, 4 from table3;
COMMIT;

Make the inserts into assigned_students reference the just-inserted rows from themes (so you can get their auto generated IDs) also:
BEGIN;
insert into themes (tutorID, year, theme_name, degreeID)
select themeID, year, work_name, degreeID from journal;
INSERT INTO assigned_students (studentID, tutorID, themeID, writing_language_id, work_typeID)
select j.studentID, j.tutorID, t.THEME_ID_COLUMN_NAME, 0, 4
from
journal j
inner join themes t on j.themeID = t.tutorid;
COMMIT
Here we see that first we make some inserts into themes, and I presume it will autogenerate some IDs for themes' pk column.
So we then join journal onto those rows we inserted so we can retrieve the generated IDs
I don't know what the PK column of themes is called, so you'll have to replace THEME_ID_COLUMN_NAME with the correct value
Note that you might have to specify additional columns in on j.themeID = t.tutorid than just the tutorid, if that doesnt uniquely identify a row
I read also that for autoincrement columns it is guaranteed that the IDs are sequential, so you can get the LAST_INSERTED_ID() which is the mos trecently inserted row) as well as the ROW_COUNT and hence know the range of IDs that was inserted, and use that to select/join the journal data

Related

Insert multiple rows in a table using a subquery

I'm trying to get all the items of the cart_items and add it to the ticket_items.
I've the error "SUBQUERY RETURN MULTIPLE ROWS", but that's what I want, insert all that rows in the ticket_items table in a same query.
INSERT INTO ticket_items (ticket_id, ISBN, quantity)
VALUES (
(SELECT COUNT(ticket_id) FROM ticket),
(SELECT ISBN FROM cart_items WHERE customer_id = 1),
(SELECT quantity FROM cart_items WHERE customer_id = 1)
);
The issue is that you are using an aggregate function (COUNT) that will build exactly one value, but both isbn and quantity occur twice or more. So, the insert that will be built by your query is something like
INSERT INTO ticket_items (ticket_id, ISBN, quantity)
VALUES (10, 1,2,3, 4,5,6);
This is of course not allowed. Since you do a COUNT, you need to apply GROUP BY to create multiple rows which will be inserted.
So your insert command will be something like this:
INSERT INTO ticket_items (ticket_id, ISBN, quantity)
((SELECT COUNT(ticket_id), ISBN, quantity
FROM ticket, cart_items
WHERE customer_id = 1
GROUP BY ISBN, quantity));
This will work correctly and do what you asked for, I created an example here: db<>fiddle
You should check if this is really what you want because for me, it doesn't make sense to insert the count of ticket_id like you describe. But this is something you must check on your own.
Don't use VALUES keyword.
Please see syntax below:
INSERT INTO table2 (column1, column2, column3, ...)
SELECT column1, column2, column3, ...
FROM table1
WHERE condition;
I would first make sure that select gives you the expected result, then issue the insert statement.
Upon review, I believe the issue is with SELECT part.
You should rewrite it as one SELECT:
INSERT INTO ticket_items (ticket_id, ISBN, quantity)
(SELECT
(SELECT COUNT(ticket_id) from ticket) as ticket_id, ISBN, quantity
FROM cart_items
WHERE customer_id = 1)
Good luck!

MaraiDB / MySQL Insert Into Table From Select Query But On Duplicate Key Use Data From Select Query

I have created table A as follows:
I put in the data above using a simple INSERT INTO and SELECT statement. Now that the source data is corrected, I want to used the INSERT INTO, SELECT, ON DUPLICATE KEY UPDATE, but when I run the code, the 0's and NULL that you see above does not update to the new value.
Here is my code
INSERT INTO
TABLEA (uniqueid, year, month, costcentre, amount)
SELECT
SS.uniquekey, SS.year, SS.month, SS.source, SS.totalamount
FROM
(SELECT
uniquekey, `YEAR`, `MONTH`, SOURCE, totalamount
FROM
TABLEB
UNION ALL
SELECT
uniquekey, `YEAR`, `MONTH`, SOURCE, totalamount
FROM
TABLEC
) as SS
ON DUPLICATE KEY
UPDATE
TABLEA.YEAR = VALUES(SS.year),
TABLEA.MONTH = VALUES(SS.month),
TABLEA.COSTCENTRE = VALUES(SS.SOURCE),
TABLEA.AMOUNT = VALUES(SS.TOTALAMOUNT)
;
So the answer I am looking for, is:
I want TABLEA to have a line for each UNIQUE that is in the SELECT query.
If TABLEA contains the same UNIQUEID as the SELECT, then I want it to update the YEAR, MONTH, COSTCENTRE, AMOUNT from the SELECT query
Converted my comment to an answer.
I believe that it should be ON DUPLICATE KEY UPDATE YEAR = VALUES(YEAR) - i.e. you should refer to the column names of TABLEA only

MySQL Insert values and some to be selected from other tables

I have 3 tables
works (id, name, date_started, date_finished, type_id, employer_id)
types (id, type)
employers (id, name, last_name, company)
I want when inserting into works table records in one query to insert into columns: name, date (by hand), then also into type_id and employer_id columns (selecting id from other tables)
I know you can insert and then use select, but how do i add the other values, that i need to type by hand as they dont exist on other tables?
You can just put the extra values directly in the SELECT clause:
INSERT INTO works (name, date_started, type_id, employer_id)
SELECT name, curdate(), type_id, employer_id
FROM types t
JOIN employers e ON ...
WHERE ...
You can have subqueries inside VALUES() clause, provided the subquery will only return one value.
INSERT INTO works (name, date_started, date_finished, type_id, employer_id)
VALUES
(
'name here',
'date started',
'date finished',
(SELECT id FROM types WHERE type = 'val' LIMIT 1),
(SELECT id FROM employers WHERE name = 'val' LIMIT 1)
)

MySQL database related

I have two tables:
purchase_mis(id, user_id, total_purchased, date)
daily_purchase(id, user_id, product_id, paid_amount, purchase_date)
I have a CRON file that runs every night, it counts the daily purchase from the "daily_purchase" table and runs insert into "purchase_mis".
For example:
SELECT
COUNT(*) AS purchase_count,
purchase_date
FROM daily_purchase
GROUP BY user_id;
This returns the purchase_count for every user and then it will be inserted to the "purchase_mis" table.
INSERT INTO
purchase_mis(user_id, total_purchased, date)
VALUES
('2', 'purchase_count', 'purchase_date');
But before inserting, it needs to check if the purchased information of user_id = 2 for some date "purchase_date" has already been inserted so it should not be inserted again.
I want something like the below query:
INSERT INTO
purchase_mis(user_id, total_purchased, date)
VALUES
('2', 'purchase_count', 'purchase_date')
WHERE date NOT EXISTS (SELECT date FROM purchase_mis WHERE user_id = '2');
Create a key on the date column, and then use INSERT IGNORE or INSERT ... ON DUPLICATE KEY UPDATE syntax. See this for more: "INSERT IGNORE" vs "INSERT ... ON DUPLICATE KEY UPDATE"
Also, you can probably use triggers or procedures instead of a cron job; might make life a bit easier.
insert into purchase_mis
(user_id, total_purchased, date)
select *
from (
select 2 as id,
100 as user_id,
str_to_date('2012-12-04', '%Y-%m-%d') as purchase_date
) t
where not exists (SELECT 1
FROM purchase_mis pm
WHERE pm.user_id = t.id
and pm.date = t.purchase_date);

How can I find which two rows have timestamps closest to each other?

I'm building a web application for location-based check ins, sort of like a local 4square, but based on RFID tags.
Anyway, each check-in is stored in a MySQL table with a userID and the time of the check-in as a DATETIME column.
Now I'd like to show which users have the closest check-in times between different stations.
Explanation: Let's say user A checked in at 21:43:12 and then again at 21:43:19. He moved between stations in 7 seconds.
There are thousands of check-ins in the database, how do I write SQL to select the users with the two closest check-in times?
Try this:
select
a.id,
b.id,
abs(a.rfid-b.rfid)
from
table1 a,
table1 a
where
a.userID=b.userID
// and any other conditions to make it a single user
group by
a.id,
b.id,
a.rfid,
b.rfid
order by
abs(a.rfid-b.rfid) desc
limit 1
Really fast solution would introduce some precalculations. Like storing the difference between current and previous checkins.
In this case you would select what you need in fast manner (as long as you cover that column by index).
Not using precalculation in this case would cause terrible queries that would operate over cartesian-like productions.
What have you tried? Have you looked at DATEDIFF
http://msdn.microsoft.com/en-us/library/ms189794.aspx
Cheers
--Jocke
First, you want an index on the user and then the timestamp.
Second, you need to use correlated sub-queries to find "the next timestamp".
Then you use GROUP BY to find the smallest interval per user.
SELECT
a.user_id,
MIN(TIMEDIFF(b.timestamp, a.timestamp)) AS min_duration,
FROM
checkin AS a
INNER JOIN
checkin AS b
ON b.user_id = a.user_id
AND b.timestamp = (SELECT MIN(timestamp)
FROM checkin
WHERE user_id = a.user_id
AND timestamp > a.timestamp)
GROUP BY
a.user_id
ORDER BY
min_duration
LIMIT
1
If you want to allow for multiple users with the same min_duration, I recommend storing the results (without the LIMIT 1) in a temporary table, then searching that table for all users that share the minimum duration.
Depending on the volume of data, this could be slow. One optimisation would be to cache the results of the TIMEDIFF(). Every time a new checkin is recorded, also calculate and store the duration since the last checkin, maybe using triggers. Having this pre-calculated makes the query simpler and the values indexable.
I figure, you only want to compute the difference between two checkins if, they are two consecutive checkins of the same person.
create table test (
id int,
person_id int,
checkin datetime);
insert into test (id, person_id, checkin) values (1, 1, now());
insert into test (id, person_id, checkin) values (2, 1, now());
insert into test (id, person_id, checkin) values (3, 2, now());
insert into test (id, person_id, checkin) values (4, 2, now());
insert into test (id, person_id, checkin) values (5, 1, now());
insert into test (id, person_id, checkin) values (6, 2, now());
insert into test (id, person_id, checkin) values (7, 1, now());
select * from (
select a.*,
(select a.checkin - b.checkin
from test b where b.person_id = a.person_id
and b.checkin < a.checkin
order by b.checkin desc
limit 1
) diff
from test a
where a.person_id = 1
order by a.person_id, a.checkin
) tt
where diff is not null
order by diff asc;
SELECT a.*, b.*
FROM table_name AS a
JOIN table_name AS b
ON a.id != b.id
ORDER BY TIMESTAMPDIFF(SECOND, a.checkin, b.checkin) ASC
LIMIT 1
Should do it. Might be a bit laggy as mentioned.