I have a temporary table called 'tempaction'. I wanted to select rows where 'ActionID' matches that of another table. I got the safe update mode error, I think as ActionID is part of a compound primary key. However, when I try
UPDATE action
SET Status = 'Sent'
WHERE ActionID IN( select ActionID from tempaction)
AND DeviceID IN( select DeviceID from tempaction);
I get temporary table cannot be reopened error.
Checking both parts of primary key has worked for the safe update error in the past. I also understand that I cannot reference a temporary table twice in the same statement.
How can I select rows with matching ActionID's or matching ActionID's AND DeviceID's from this temporary table?
Tempory Table
CREATE TEMPORARY TABLE tempaction (ActionID BIGINT)
SELECT *
FROM action
WHERE DeviceID = '1234'
AND Status = 'Pending'
You can try Update using Join with sub-query.
UPDATE action a
JOIN
tempaction t ON a.ActionID = t.ActionID
SET
a.Status = 'Sent';
Related
I am running a query directly in MySQL Workbench. It is a work in progress, but I can't get past this issue.
The query is as follows:
#Temporary table to hold dcsIds that are past grace period
CREATE TABLE pastGracePeriod (
dcsId varchar(50) NOT NULL
);
INSERT INTO pastGracePeriod
SELECT dcsId FROM loyaltyOptOutGracePeriod
WHERE optOutDate <= ADDDATE(CURRENT_TIMESTAMP(), INTERVAL -15 DAY);
#temporary table to hold dcsIds that are validated against subscriptions table
CREATE TABLE validatedDcsIds (
dcsId varchar(50) NOT NULL
);
INSERT INTO validatedDcsIds
SELECT subscriptions.dcsId
FROM subscriptions
INNER JOIN pastGracePeriod ON subscriptions.dcsId = pastGracePeriod.dcsId
WHERE subscriptions.optOutDate <= ADDDATE(CURRENT_TIMESTAMP(), INTERVAL -15 DAY)
AND subscriptions.subscriptionId IN (24,25,30)
AND subscriptions.optInStatus='N';
#delete items in validatedDcsIds table from externalId table
DELETE FROM externalId
WHERE EXISTS (SELECT dcsId FROM validatedDcsIds
WHERE externalId.dcsId = validatedDcsIds.dcsId);
DROP TABLE pastGracePeriod;
DROP TABLE validatedDcsIds;
The query takes dcsIds (PK) from a table called loyaltyOptOutGracePeriod, validates them against another table called subscriptions, then takes those validated dcsIds and deletes them from a table called externalId.
The query works fine until it gets to the DELETE clause. In the externalId table, the PK is a composite key consisting of fields dcsId, appId, and appName. As it is written above, I get Error 1175: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column.
If I change it to:
DELETE FROM externalId
WHERE EXISTS (SELECT dcsId FROM validatedDcsIds
WHERE externalId_backup.dcsId = validatedDcsIds.dcsId)
AND appId <> NULL;
I get no errors, but nothing gets deleted from the externalId table as expected.
I am at a loss, any suggestions are very welcome!
NOTE: I do not need to know how to disable safe update mode.
Do not use WHERE EXISTS. Use Multiple-Table Syntax:
DELETE table1
FROM table1
JOIN table2 ON {joining conditions}
WHERE {additional conditions}
I know, deleting duplicates from mysql is often discussed here. But none of the solution work fine within my case.
So, I have a DB with Address Data nearly like this:
ID; Anrede; Vorname; Nachname; Strasse; Hausnummer; PLZ; Ort; Nummer_Art; Vorwahl; Rufnummer
ID is primary Key and unique.
And i have entrys for example like this:
1;Herr;Michael;Müller;Testweg;1;55555;Testhausen;Mobile;012345;67890
2;Herr;Michael;Müller;Testweg;1;55555;Testhausen;Fixed;045678;877656
The different PhoneNumber are not the problem, because they are not relevant for me. So i just want to delete the duplicates in Lastname, Street and Zipcode. In that case ID 1 or ID 2. Which one of both doesn't matter.
I tried it actually like this with delete:
DELETE db
FROM Import_Daten db,
Import_Daten dbl
WHERE db.id > dbl.id AND
db.Lastname = dbl.Lastname AND
db.Strasse = dbl.Strasse AND
db.PLZ = dbl.PLZ;
And insert into a copy table:
INSERT INTO Import_Daten_1
SELECT MIN(db.id),
db.Anrede,
db.Firstname,
db.Lastname,
db.Branche,
db.Strasse,
db.Hausnummer,
db.Ortsteil,
db.Land,
db.PLZ,
db.Ort,
db.Kontaktart,
db.Vorwahl,
db.Durchwahl
FROM Import_Daten db,
Import_Daten dbl
WHERE db.lastname = dbl.lastname AND
db.Strasse = dbl.Strasse And
db.PLZ = dbl.PLZ;
The complete table contains over 10Mio rows. The size is actually my problem. The mysql runs on a MAMP Server on a Macbook with 1,5GHZ and 4GB RAM. So not really fast. SQL Statements run in a phpmyadmin. Actually i have no other system possibilities.
You can write a stored procedure that will each time select a different chunk of data (for example by rownumber between two values) and delete only from that range. This way you will slowly bit by bit delete your duplicates
A more effective two table solution can look like following.
We can store only the data we really need to delete and only the fields that contain duplicate information.
Let's assume we are looking for duplicate data in Lastname , Branche, Haushummer fields.
Create table to hold the duplicate data
DROP TABLE data_to_delete;
Populate the table with data we need to delete ( I assume all fields have VARCHAR(255) type )
CREATE TABLE data_to_delete (
id BIGINT COMMENT 'this field will contain ID of row that we will not delete',
cnt INT,
Lastname VARCHAR(255),
Branche VARCHAR(255),
Hausnummer VARCHAR(255)
) AS SELECT
min(t1.id) AS id,
count(*) AS cnt,
t1.Lastname,
t1.Branche,
t1.Hausnummer
FROM Import_Daten AS t1
GROUP BY t1.Lastname, t1.Branche, t1.Hausnummer
HAVING count(*)>1 ;
Now let's delete duplicate data and leave only one record of all duplicate sets
DELETE Import_Daten
FROM Import_Daten LEFT JOIN data_to_delete
ON Import_Daten.Lastname=data_to_delete.Lastname
AND Import_Daten.Branche=data_to_delete.Branche
AND Import_Daten.Hausnummer = data_to_delete.Hausnummer
WHERE Import_Daten.id != data_to_delete.id;
DROP TABLE data_to_delete;
You can add a new column e.g. uq and make it UNIQUE.
ALTER TABLE Import_Daten
ADD COLUMN `uq` BINARY(16) NULL,
ADD UNIQUE INDEX `uq_UNIQUE` (`uq` ASC);
When this is done you can execute an UPDATE query like this
UPDATE IGNORE Import_Daten
SET
uq = UNHEX(
MD5(
CONCAT(
Import_Daten.Lastname,
Import_Daten.Street,
Import_Daten.Zipcode
)
)
)
WHERE
uq IS NULL;
Once all entries are updated and the query is executed again, all duplicates will have the uq field with a value=NULL and can be removed.
The result then is:
0 row(s) affected, 1 warning(s): 1062 Duplicate entry...
For newly added rows always create the uq hash and and consider using this as the primary key once all entries are unique.
I must create a mysql query with a large number of queries (about 150,000)
For the moment the query is:
UPDATE table SET activated=NULL
WHERE (
id=XXXX
OR id=YYYY
OR id=ZZZZ
OR id=...
...
)
AND activated IS NOT NULL
Do you know a best way for to do that please?
If you're talking about thousands of items, an IN clause probably isn't going to work. In that case you would want to insert the items into a temporary table, then join with it for the update, like so:
UPDATE table tb
JOIN temptable ids ON ids.id = tb.id
SET tb.activated = NULL
UPDATE table
SET activated = NULL
WHERE id in ('XXXX', 'YYYY', 'zzzz')
AND activated IS NOT NULL
I have to write a Stored Procedure to delete record from a table.
I have a memory table "tableids" where I store all the ids to delete from another table, say "addresses".
CREATE TABLE `tempids` (
`id` INT(11) NULL DEFAULT NULL
)
COLLATE='latin1_swedish_ci'
ENGINE=MEMORY
ROW_FORMAT=DEFAULT
I could do this:
DELETE FROM addresses INNER JOIN tempids ON addresses.id = tempids.id;
BUT I want to physically delete the records in the addresses table if they have no references in other known tables in my model; otherwise I want to delete the records logically. I'd like to do this in a single shot, that is without writing a loop in my SP.
In pseudo-sql code:
DELETE
FROM addresses
WHERE
id NOT IN (SELECT address_id FROM othertable1 WHERE address_id=(SELECT id FROM tempids))
AND id NOT IN (SELECT address_id FROM othertable2 WHERE address_id=(SELECT id FROM tempids))
...more possible references in other tables
IF "no records deleted"
DELETE FROM addresses INNER JOIN tempids ON addresses.id = tempids.id;
ELSE
UPDATE addresses SET deleted=TRUE INNER JOIN tempids ON addresses.id = tempids.id;
How do I accomplish this?
Thanks.
You can check ROW_COUNT() function value after deleting.
http://dev.mysql.com/doc/refman/5.5/en/information-functions.html#function_row-count
So "no records deleted" condition is replaced with ROW_COUNT() == 0
I need to query a delete statement for the same table based on column conditions from the same table for a correlated subquery.
I can't directly run a delete statement and check a condition for the same table in mysql for a correlated subquery.
I want to know whether using temp table will affect mysql's memory/performance?
Any help will be highly appreciated.
Thanks.
You can make mysql do the temp table for you by wrapping your "where" query as an inline from table.
This original query will give you the dreaded "You can't specify target table for update in FROM clause":
DELETE FROM sametable
WHERE id IN (
SELECT id FROM sametable WHERE stuff=true
)
Rewriting it to use inline temp becomes...
DELETE FROM sametable
WHERE id IN (
SELECT implicitTemp.id from (SELECT id FROM sametable WHERE stuff=true) implicitTemp
)
Your question is really not clear, but I would guess you have a correlated subquery and you're having trouble doing a SELECT from the same table that is locked by the DELETE. For instance to delete all but the most recent revision of a document:
DELETE FROM document_revisions d1 WHERE edit_date <
(SELECT MAX(edit_date) FROM document_revisions d2
WHERE d2.document_id = d1.document_id);
This is a problem for MySQL.
Many examples of these types of problems can be solved using MySQL multi-table delete syntax:
DELETE d1 FROM document_revisions d1 JOIN document_revisions d2
ON d1.document_id = d2.document_id AND d1.edit_date < d2.edit_date;
But these solutions are best designed on a case-by-case basis, so if you edit your question and be more specific about the problem you're trying to solve, perhaps we can help you.
In other cases you may be right, using a temp table is the simplest solution.
can't directly run a delete statement and check a condition for the same table
Sure you can. If you want to delete from table1 while checking the condition that col1 = 'somevalue', you could do this:
DELETE
FROM table1
WHERE col1 = 'somevalue'
EDIT
To delete using a correlated subquery, please see the following example:
create table project (id int);
create table emp_project (id int, project_id int);
insert into project values (1);
insert into project values (2);
insert into emp_project values (100, 1);
insert into emp_project values (200, 1);
/* Delete any project record that doesn't have associated emp_project records */
DELETE
FROM project
WHERE NOT EXISTS
(SELECT *
FROM emp_project e
WHERE e.project_id = project.id);
/* project 2 doesn't have any emp_project records, so it was deleted, now
we have 1 project record remaining */
SELECT * FROM project;
Result:
id
1
Create a temp table with the values you want to delete, then join it to the table while deleting. In this example I have a table "Games" with an ID column. I will delete ids greater than 3. I will gather the targets in a temp table first so I can report on them later.
DECLARE #DeletedRows TABLE (ID int)
insert
#DeletedRows
(ID)
select
ID
from
Games
where
ID > 3
DELETE
Games
from
Games g
join
#DeletedRows x
on x.ID = g.ID
I have used group by aggregate with having clause and same table, where the query was like
DELETE
FROM TableName
WHERE id in
(select implicitTable.id
FROM (
SELECT id
FROM `TableName`
GROUP by id
HAVING count(id)>1
) as implicitTable
)
You mean something like:
DELETE FROM table WHERE someColumn = "someValue";
?
This is definitely possible, read about the DELETE syntax in the reference manual.
You can delete from same table. Delete statement is as follows
DELETE FROM table_name
WHERE some_column=some_value