УДАЛИТЬ строки из двух таблиц, которые не имеют идентификатора, совпадают с другим запросом тех же двух таблиц - PullRequest
0 голосов
/ 02 февраля 2019

Следующее не обязательно использует правильный синтаксис, но предназначено, чтобы передать мое намерение:

DELETE FROM wp_posts, wp_postmeta 
 WHERE wp_posts.ID <> min(f.post_ID), wp_postmeta.post_id <> min(f.post_ID) 

(Это действительно два удаления, объединенные в одном, с условием WHERE для первой и второй таблиц соответственно.)

, где min(f.post_ID) происходит из виртуальной таблицы ниже:

SELECT Min(f.post_id), 
       f.post_title, 
       f.meta_value 
FROM   (SELECT wp_posts.post_title, 
               Min(wp_postmeta.meta_value) AS minprice 
        FROM   wp_postmeta 
               JOIN wp_posts 
                 ON wp_postmeta.post_id = wp_posts.id 
        WHERE  wp_posts.post_type = 'Product' 
               AND wp_postmeta.meta_key = '_regular_price' 
        GROUP  BY wp_posts.post_title) AS x 
       INNER JOIN (SELECT wp_postmeta.post_id, 
                          wp_posts.post_title, 
                          wp_postmeta.meta_value 
                   FROM   wp_postmeta 
                          JOIN wp_posts 
                            ON wp_postmeta.post_id = wp_posts.id 
                   WHERE  wp_posts.post_type = 'Product' 
                          AND wp_postmeta.meta_key = '_regular_price' 
                   ORDER  BY wp_posts.post_title, 
                             wp_postmeta.meta_value) AS f 
               ON x.post_title = f.post_title 
                  AND f.meta_value = x.minprice 
GROUP  BY f.post_title 

Как будет выглядеть запрос?

Редактировать: Стоит учесть, что любая реализация, которая удаляет изодна таблица перед другой изменит результат второго удаления.(Первое УДАЛЕНИЕ будет затронуто первым удалением, поскольку элементы из таблицы в подзапросе были удалены в первом УДАЛИТЬ.)

Ответы [ 2 ]

0 голосов
/ 02 февраля 2019

Идея состоит в том, чтобы выбрать идентификаторы для удаления из таблиц wp_posts и wp_postmeta во временные таблицы posts и postmeta.Это сохранит список идентификаторов, даже если вы удалите данные из любой таблицы.Затем удалите данные из таблиц wp_posts и wp_postmeta одну за другой на основе списка идентификаторов во временных таблицах.Последний шаг - очистка временных таблиц (удаление данных из них).

Транзакция используется таким образом, чтобы разрешить запуск этого кода в PHPMyAdmin.

Оптимальная версия кода:

BEGIN;

CREATE TEMPORARY TABLE IF NOT EXISTS minPostIds AS 
    SELECT Min(f.post_id)
    FROM   (SELECT wp_posts.post_title, 
               Min(wp_postmeta.meta_value) AS minprice 
        FROM   wp_postmeta 
               JOIN wp_posts 
                 ON wp_postmeta.post_id = wp_posts.id 
        WHERE  wp_posts.post_type = 'Product' 
               AND wp_postmeta.meta_key = '_regular_price' 
        GROUP  BY wp_posts.post_title) AS x 
        INNER JOIN (SELECT wp_postmeta.post_id, 
                          wp_posts.post_title, 
                          wp_postmeta.meta_value 
                   FROM   wp_postmeta 
                          JOIN wp_posts 
                            ON wp_postmeta.post_id = wp_posts.id 
                   WHERE  wp_posts.post_type = 'Product' 
                          AND wp_postmeta.meta_key = '_regular_price') AS f 
               ON x.post_title = f.post_title 
                  AND f.meta_value = x.minprice 
        GROUP  BY f.post_title;


DELETE FROM wp_posts WHERE wp_posts.ID IN (SELECT ID FROM minPostIds);
DELETE FROM wp_postmeta WHERE wp_postmeta.post_id IN (SELECT ID FROM minPostIds); 

DELETE FROM minPostIds;

COMMIT;

Эта версия работает:

BEGIN;

CREATE TEMPORARY TABLE IF NOT EXISTS posts AS 
    SELECT ID
    FROM wp_posts
    WHERE wp_posts.ID NOT IN 
    (
        SELECT Min(f.post_id)
        FROM   (SELECT wp_posts.post_title, 
                   Min(wp_postmeta.meta_value) AS minprice 
            FROM   wp_postmeta 
                   JOIN wp_posts 
                     ON wp_postmeta.post_id = wp_posts.id 
            WHERE  wp_posts.post_type = 'Product' 
                   AND wp_postmeta.meta_key = '_regular_price' 
            GROUP  BY wp_posts.post_title) AS x 
            INNER JOIN (SELECT wp_postmeta.post_id, 
                              wp_posts.post_title, 
                              wp_postmeta.meta_value 
                       FROM   wp_postmeta 
                              JOIN wp_posts 
                                ON wp_postmeta.post_id = wp_posts.id 
                       WHERE  wp_posts.post_type = 'Product' 
                              AND wp_postmeta.meta_key = '_regular_price' 
                       ORDER  BY wp_posts.post_title, 
                                 wp_postmeta.meta_value) AS f 
                   ON x.post_title = f.post_title 
                      AND f.meta_value = x.minprice 
            GROUP  BY f.post_title
);



CREATE TEMPORARY TABLE IF NOT EXISTS postmeta AS     
SELECT post_id
    FROM wp_postmeta
    WHERE wp_postmeta.post_id NOT IN 
    (
        SELECT Min(f.post_id)
        FROM   (SELECT wp_posts.post_title, 
                   Min(wp_postmeta.meta_value) AS minprice 
            FROM   wp_postmeta 
                   JOIN wp_posts 
                     ON wp_postmeta.post_id = wp_posts.id 
            WHERE  wp_posts.post_type = 'Product' 
                   AND wp_postmeta.meta_key = '_regular_price' 
            GROUP  BY wp_posts.post_title) AS x 
            INNER JOIN (SELECT wp_postmeta.post_id, 
                              wp_posts.post_title, 
                              wp_postmeta.meta_value 
                       FROM   wp_postmeta 
                              JOIN wp_posts 
                                ON wp_postmeta.post_id = wp_posts.id 
                       WHERE  wp_posts.post_type = 'Product' 
                              AND wp_postmeta.meta_key = '_regular_price' 
                       ORDER  BY wp_posts.post_title, 
                                 wp_postmeta.meta_value) AS f 
                   ON x.post_title = f.post_title 
                      AND f.meta_value = x.minprice 
            GROUP  BY f.post_title
);


DELETE FROM wp_posts WHERE wp_posts.ID IN (SELECT ID FROM posts);

DELETE FROM wp_postmeta WHERE wp_postmeta.post_id IN (SELECT post_id FROM postmeta);

DELETE FROM posts;
DELETE FROM postmeta;

COMMIT;

Вы также можете создать хранимую процедуру:

CREATE PROCEDURE DeleteFromTables()
BEGIN
CREATE TEMPORARY TABLE IF NOT EXISTS posts 
ENGINE=MyISAM 
AS (
    SELECT ID
    FROM wp_posts
    WHERE wp_posts.ID NOT IN 
    (
        SELECT Min(f.post_id)
        FROM   (SELECT wp_posts.post_title, 
                   Min(wp_postmeta.meta_value) AS minprice 
            FROM   wp_postmeta 
                   JOIN wp_posts 
                     ON wp_postmeta.post_id = wp_posts.id 
            WHERE  wp_posts.post_type = 'Product' 
                   AND wp_postmeta.meta_key = '_regular_price' 
            GROUP  BY wp_posts.post_title) AS x 
            INNER JOIN (SELECT wp_postmeta.post_id, 
                              wp_posts.post_title, 
                              wp_postmeta.meta_value 
                       FROM   wp_postmeta 
                              JOIN wp_posts 
                                ON wp_postmeta.post_id = wp_posts.id 
                       WHERE  wp_posts.post_type = 'Product' 
                              AND wp_postmeta.meta_key = '_regular_price' 
                       ORDER  BY wp_posts.post_title, 
                                 wp_postmeta.meta_value) AS f 
                   ON x.post_title = f.post_title 
                      AND f.meta_value = x.minprice 
            GROUP  BY f.post_title
    )
);



CREATE TEMPORARY TABLE IF NOT EXISTS postmeta
ENGINE=MyISAM 
AS (
    SELECT post_id
    FROM wp_postmeta
    WHERE wp_postmeta.post_id NOT IN 
    (
        SELECT Min(f.post_id)
        FROM   (SELECT wp_posts.post_title, 
                   Min(wp_postmeta.meta_value) AS minprice 
            FROM   wp_postmeta 
                   JOIN wp_posts 
                     ON wp_postmeta.post_id = wp_posts.id 
            WHERE  wp_posts.post_type = 'Product' 
                   AND wp_postmeta.meta_key = '_regular_price' 
            GROUP  BY wp_posts.post_title) AS x 
            INNER JOIN (SELECT wp_postmeta.post_id, 
                              wp_posts.post_title, 
                              wp_postmeta.meta_value 
                       FROM   wp_postmeta 
                              JOIN wp_posts 
                                ON wp_postmeta.post_id = wp_posts.id 
                       WHERE  wp_posts.post_type = 'Product' 
                              AND wp_postmeta.meta_key = '_regular_price' 
                       ORDER  BY wp_posts.post_title, 
                                 wp_postmeta.meta_value) AS f 
                   ON x.post_title = f.post_title 
                      AND f.meta_value = x.minprice 
            GROUP  BY f.post_title 
    )
);


START TRANSACTION;

    DELETE FROM wp_posts
    WHERE wp_posts.ID IN (SELECT ID FROM posts);

    DELETE FROM wp_postmeta
    WHERE wp_postmeta.post_id IN (SELECT post_id FROM postmeta);

COMMIT;

DELETE FROM posts;
DELETE FROM postmeta;
END;
0 голосов
/ 02 февраля 2019

Вы не удаляете из двух таблиц одновременно.Если таблицы связаны, вы удаляете из дочернего, то из родительского.Если они не связаны, удаление может произойти в любом порядке.Если они не связаны, но имеют другие таблицы в зависимости от них (т.е. они сами являются родителями и имеют детей), то сначала необходимо удалить данные из этих других таблиц.Если реляционные ограничения установлены в режим CASCADE DELETE, то данные дочерней таблицы будут автоматически удаляться при удалении данных родительской таблицы.Если удаление должно происходить как действие «все или ничего» (т. Е. Если второе удаление завершается неудачно после успешного первого удаления, вы не хотите, чтобы первое удаление было успешным), это следует делать в транзакции.

Таким образом:

DELETE FROM wp_postmeta WHERE post_id NOT IN (

  SELECT Min(f.post_id)
  FROM   (SELECT wp_posts.post_title, 
           Min(wp_postmeta.meta_value) AS minprice 
    FROM   wp_postmeta 
           JOIN wp_posts 
             ON wp_postmeta.post_id = wp_posts.id 
    WHERE  wp_posts.post_type = 'Product' 
           AND wp_postmeta.meta_key = '_regular_price' 
    GROUP  BY wp_posts.post_title) AS x 
   INNER JOIN (SELECT wp_postmeta.post_id, 
                      wp_posts.post_title, 
                      wp_postmeta.meta_value 
               FROM   wp_postmeta 
                      JOIN wp_posts 
                        ON wp_postmeta.post_id = wp_posts.id 
               WHERE  wp_posts.post_type = 'Product' 
                      AND wp_postmeta.meta_key = '_regular_price' 
               ORDER  BY wp_posts.post_title, 
                         wp_postmeta.meta_value) AS f 
           ON x.post_title = f.post_title 
              AND f.meta_value = x.minprice 
  GROUP  BY f.post_title
)

DELETE FROM wp_posts WHERE ID NOT IN (

  SELECT Min(f.post_id)
  FROM   (SELECT wp_posts.post_title, 
           Min(wp_postmeta.meta_value) AS minprice 
    FROM   wp_postmeta 
           JOIN wp_posts 
             ON wp_postmeta.post_id = wp_posts.id 
    WHERE  wp_posts.post_type = 'Product' 
           AND wp_postmeta.meta_key = '_regular_price' 
    GROUP  BY wp_posts.post_title) AS x 
   INNER JOIN (SELECT wp_postmeta.post_id, 
                      wp_posts.post_title, 
                      wp_postmeta.meta_value 
               FROM   wp_postmeta 
                      JOIN wp_posts 
                        ON wp_postmeta.post_id = wp_posts.id 
               WHERE  wp_posts.post_type = 'Product' 
                      AND wp_postmeta.meta_key = '_regular_price' 
               ORDER  BY wp_posts.post_title, 
                         wp_postmeta.meta_value) AS f 
           ON x.post_title = f.post_title 
              AND f.meta_value = x.minprice 
  GROUP  BY f.post_title
)

Предупреждение

Не запускайте запрос на удаление, данный вам кем-то в Интернете, без предварительного резервного копирования ваших данных.По крайней мере, запустите транзакцию, запустите удаление, выберите результаты и посмотрите на них, чтобы убедиться, что они правильные, используя следующий код:

START TRANSACTION;
DELETE FROM ...
DELETE FROM ...
SELECT * FROM ... -/*to check the deletes worked and didn't remove too much*/
ROLLBACK;

Измените ROLLBACK на COMMIT, когда вы 're happy

Редактировать:

Вариант 1

Заставить метаданные постов зависеть от постов (это может уже иметь место, убедитесь, что удаления каскадируются):

ALTER TABLE posts_meta
ADD CONSTRAINT fk_pm FOREIGN KEY (posts_id) REFERENCES posts(id) ON DELETE CASCADE

Теперь запустите удаление в таблице сообщений, записи posts_meta также исчезнут

Option2

Запустите удаление в таблице сообщений, как указано выше

Используйте следующий запрос дляудалить любую запись из posts_meta, у которой нет соответствующей записи в сообщениях:

DELETE FROM posts_meta WHERE post_id IN (select post_id from(
  SELECT pm.post_id 
  FROM
    posts_meta pm
    LEFT JOIN 
    posts p
    ON p.id = pm.post_id
  WHERE
    p.id IS NULL

) i )

Внутренний подзапрос, который находит список идентификаторов, по какой-то причине обернут внутри другого подзапроса;Есть ситуации, когда MySQL откажется от удаления, если шаблон DELETE FROM x WHERE y IN (SELECT x FROM y), потому что вы не можете изменить таблицу, из которой выбираете.Заключение в другой выбор - это хак, который заставляет MySQL не рассматривать его как удаление из той же таблицы, которую вы выбираете из

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...