I copied some records from one table to another
with this query :
insert into pages_finished (keyword,pages,resultlist,done,current)
select keyword,pages,resultlist,done,current
from pages_done o
where (select count(*) as totalPages from pages_done x where x.keyword = o.keyword)-1 = pages
Now I want to delete the same records from the source table,
I was thinking it would be simple as:
delete from pages_done o
where (select count(*) as totalPages from pages_done x where x.keyword = o.keyword)-1 = pages
but that doesn't work.
Could anyone tell me what is the right way to do that?
After #bgdrl answer, I'm thinking about running only the select,
get the id's of all records that should be copied,
and then delete;
but I think there must be an easier solution, anyone?
Even though marked #bgdrl answer as the right answer,
it is only because of that a fact.
To anyone interested with what I ended up doing :
I did the same select I started with (but selected only the id column, since selecting all the columns would have killed my poor computer),
exported it to an INSERT STATMENTS (using mysqlworkbench),
opened the text file in notepad,
replaced all the INSERT INTO... with DELETE FROM WHERE ID=,
and run that query in mysql.
I feel so stupid using this way, but had no other choice apparently.
From mysql site: "You cannot modify a table and select from the same table in a subquery. This applies to statements such as DELETE, INSERT, REPLACE, UPDATE". http://dev.mysql.com/doc/refman/5.1/en/subqueries.html
PLEASE BACKUP THE TABLE BEFORE FOLLOWING THE STEPS.
Follow the following STEPS
STEP 1
CREATE TABLE pages_done_ids
SELECT o.id FROM pages_done AS o
WHERE
(
SELECT count(*) AS totalPages
FROM pages_done AS x
WHERE x.keyword = o.keyword
)-1 = o.pages
STEP 2
DELETE FROM pages_done AS o
WHERE o.id IN (SELECT id FROM pages_done_ids)
STEP 3
DROP TABLE pages_done_ids;
OK, you may accomplish it with one transaction using TEMPORARY TABLES.
Happy Querying!
Related
This SO post is a follow up question to my SO post. I created a new post since the original question was answered and did not want to distract from answer. In experimenting with the previous solution, it got me thinking and thus this SO question was born.
Reference: DB Fiddle where I'm performing an INSERT INTO with Select in MySQL. In playing around with the data, is it possible to grab some data from the destination table matching a PK field (coreID = :org_coreID) and then combining that with a select statement to perform an INSERT INTO with Select using a :new_coreID?
I know this SQL is invalid but I'm hoping the statement below will help explain the data columns I need to insert into the steps table.
INSERT INTO steps(coreid, wolid, venueID,aid, tcount, rCount, pMax, groupID)
SELECT
a.coreID,
IFNULL(s.woLID, 0) as woLID,
s.venueID,
a.aID,
(select tCount, rCount, pMax, groupID from steps where coreID = :orig_coreID)
FROM
activity a Left Join
step s On s.aID = a.aID
WHERE
a.coreID = :new_coreID;
Is something like this possible?
I am working on a system (with Laravel) where users can fill a few filters to get the data they need.
Data is not prepared real time, once the filters are set, a job is pushed to the queue and once the query finishes a CSV file is created. Then the user receives an email with the file which was created so that they can download it.
I have seen some errors in the jobs where it took longer than 30 mins to process one job and when I checked I have seen some users created filter with more than 600 values.
This filter values are translated like this:
SELECT filed1,
field2,
field6
FROM table
INNER JOIN table2
ON table.id = table2.cid
/* this is how we try not to give same data to the users again so we used NOT IN */
WHERE table.id NOT IN(SELECT data_id
FROM data_access
WHERE data_user = 26)
AND ( /* this bit is auto populated with the filter values */
table2.filed_a = 'text a'
OR table2.filed_a = 'text b'
OR table2.filed_a = 'text c' )
Well I was not expecting users to go wild and fine tune with a huge filter set. It is okay for them to do this but need a solution to make this query quicker.
One way is to create a temp table on the fly with the filter values and covert the query for INNER JOIN but not sure if it would increase the performance.
Also, given that in a normal day system would need to create at least 40-ish temp tables and delete them afterwards. Would this become another issue in the long run?
I would love to hear any other suggestions that may help me solve this issue other then temp table method.
I would suggest writing the query like this:
SELECT ?.filed1, ?.field2, ?.field6 -- qualify column names (but no effect on performance)
FROM table t JOIN
table2 t2
ON t.id = t2.cid
WHERE NOT EXISTS (SELECT 1
FROM data_access da
WHERE t.id = da.data_id AND da.data_user = 26
) AND
t2.filed_a IN ('text a', 'text b', 'text c') ;
Then I would recommend indexes. Most likely:
table2(filed_a, cid)
table1(id) (may not be necessary if id is already the primary key)
data_access(data_id, data_user)
You can test this as your own query. I don't know how to get Laravel to produce this (assuming it meets your performance objectives).
I have read other posts and I really don't understand what I am doing wrong here because it is such a simple statement.
anything in '()' are comments
Query:
[UPDATE users, sites
SET users.idSiteRegUsers='1'
WHERE sites.SiteActivateSites='DEL' ]
(TBL's to select to update within the whole query)
(Setting the users tbl idSiteRegUsers to 1)
(Where only the sites in tbl sites = DEL)
I've also read http://bugs.mysql.com/bug.php?id=52651 and tried changing the INT to VARCHAR and UPDATING 0 to DEL due to the bug but still same result.
Issue:
I have 2129 records that need updating as found using a simple select statement to understand the number of results.
([SELECT
sites.SiteActivateSites,
sites.id_Sites,
users.idSiteRegUsers,
users.CompanyNameUsers,
sites.LinkNameSites
FROM
users
INNER JOIN sites ON users.idSiteRegUsers = sites.id_Sites
WHERE
sites.SiteActivateSites != '1']) 'simple'
But the UPDATE query updates all 4000+ records, not just the records that = DEL but the ones that are reference to another value e.g. = 1.
Have I missed something?
Cheers,
Joe
Just as with your SELECT command, you need to tell MySQL how the tables are joined: your UPDATE is currently doing a full cartesian product of both tables (with every row in users joined with every row in sites - therefore the WHERE condition filtering on sites is still resulting in a match on every record from users).
Try instead:
UPDATE users JOIN sites ON users.idSiteRegUsers = sites.id_Sites
SET users.idSiteRegUsers='1'
WHERE sites.SiteActivateSites='DEL'
I want to copy an existing MySQL table over to a duplicate table, but with two additional fields populated by data retrieved from other queries. It's for a forums software that never captured the original creation date of the thread (it always overwrote the time with the most recent reply).
So I want to take the existing table, 'threads'
thread_id
thread_author
thread_subject
thread_last_reply_date
and create a new table, 'new_threads' of the same structure, but with two extra fields:
thread_id
thread_author
thread_subject
thread_last_reply_date
thread_creation_date
thread_last_poster_id
Both thread_last_reply_date and thread_last_poster_id could be populated from dependent queries.. For example, last_poster_id with a query of:
SELECT post_author FROM posts WHERE thread_id = ? AND post_date = thread_last_reply_date
And for the thread_creation_date:
SELECT MIN(post_date) FROM posts WHERE thread_id = ?
That's essentially the process I would do with a PHP script.. A series of SELECTs and then inserting records one by one. Any advice or direction on how to do this type of process in pure SQL would be crazy helpful (if it's possible).
EDIT: an example of the technique would be helpful. I don't need an exact answer for the above. I'm sure everyone has better things to do.
Just had a similar problem.
This solution worked for me:
INSERT INTO `new_thread` SELECT *,null,null FROM `thread` WHERE 1=1
To create your target table (empty):
CREATE TABLE new_threads
SELECT t.*, thread_creation_date date, thread_last_poster_id number
FROM thread where 1=0;
and to populate it:
insert into new_threads(thread_id, thread_author, thread_subject, thread_last_reply_date, thread_creation_date, thread_last_poster_id)
(select t.*,
min(p.post_date),
(SELECT p1.post_author
FROM posts p1
WHERE p1.thread_id = t.thread_id
AND p1.post_date = t.thread_last_reply_date) thread_last_poster_id
from threads t, posts p
where t.thread_id = p.thread_id;
(untested)
I'm hesitant to run this query which deletes data (for obvious reasons).
I would like to delete the the matching rows from two tables, where the ID = the ID of a third table (which i want to remain unaffected)
This is the exact query I would like to run:
DELETE FROM ItemTracker_dbo.Transaction t,
ItemTracker_dbo.Purchase p
USING ItemTracker_dbo.Transaction
INNER JOIN ItemTracer_dbo.Purchase ON p.Transaction_ID = t.Transaction_ID
INNER JOIN ItemTracker_dbo.Item i ON i.Item_ID = p.Item_ID
WHERE i.Client_ID = 1
To test this, i tried running a select replacing DELETE FROM with SELECT * FROM, and I get a syntax error 'near USING'. When I remove USING ... it selects EVERY row in the table (ignoring the client_id=1 clause).
I (essentially) copied the syntax from the mysql manual (obviously replacing the values).
Is this query valid?
I'm sorry I didn't comment instead of post, but I just don't have enough reputation. Why don't you run it as a transaction and see the results? Or am I missing something?
http://dev.mysql.com/doc/refman/5.0/en/commit.html
As far as I know, you can't do that. The way to acomplish that is with a transaction.
START TRANSACTION;
DELETE FROM tableOne WHERE criteria;
DELETE FROM tableTwo WHERE criteria;
COMMIT;
If something goes wrong between the statements, you can issue a ROLLBACK and your data will be there.
The catch is, THIS WON'T WORK WITH MyISAM. MyISAM doesn't support transactions, so it will simply delete the data and there is no way to roll it back. They need to be InnoDB tables. It does this silently. I've lost a production table that way (good thing I had a backup and it wasn't updated much).
Easiest way to find out if the tables are InnoDB?
SHOW CREATE TABLE tableName;
At the end, it will have something like 'Engine = InnoDB' or 'Engine = MyISAM'.
I'm not familiar with this (non-standard?) use of USING to join tables in the above, but if you just want to delete rows from only some of the tables in the join the normal way would be:
DELETE Purchase, `Transaction`
FROM Item
JOIN Purchase ON Purchase.Item_ID=Item.Item_ID
JOIN `Transaction` ON `Transaction`.Transaction_ID=Purchase.Transaction_ID
WHERE Item.Client_ID=1;
Assuming I understand your schema right. It seems a bit unusual to be deleting the Transaction that is referenced from the Purchase as this would naturally be a many-Purchases-to-one-Transaction relation. Is there a UNIQUE constraint to ensure it is one-to-one? If not, can you be sure no other Purchase will be referencing the deleted Transaction?
You can test the above construct as a SELECT simply:
SELECT Purchase.Purchase_ID, `Transaction`.Transaction_ID
FROM Item ...