使用mysql在某些条件下删除行

I want to automatically delete rows when the table (shown below) gets a new insert, if certain conditions are met.

When:

  • There are rows referring to the same 'field' with the same 'user_id'
  • Their 'field', 'display' and 'search' columns are the same

Simply, when the rows would become duplicates (except the 'group_id' column) the non null 'group_id' should be deleted, otherwise a row should be updated or inserted.

Is there a way to set this up in mysql (in spirit of "ON DUPLICATE do stuff" combined with unique keys etc.), or do I have to explicitly check for it in php (with multiple queries)?

Additional info: There should always be a row with NULL 'group_id' for every possible 'field' (there's a limited set, defined elsewhere). On the other hand there might not be one with a non null 'group_id'.

CREATE TABLE `Views` (
`user_id` SMALLINT(5) UNSIGNED NOT NULL,
`db` ENUM('db_a','db_b') NOT NULL COLLATE 'utf8_swedish_ci',
`field` VARCHAR(40) NOT NULL COLLATE 'utf8_swedish_ci',
`display` TINYINT(1) UNSIGNED NOT NULL,
`search` TINYINT(1) UNSIGNED NOT NULL,
`group_id` SMALLINT(6) UNSIGNED NULL DEFAULT NULL,
UNIQUE INDEX `user_id` (`field`, `db`, `user_id`),
INDEX `Views_ibfk_1` (`user_id`),
INDEX `group_id` (`group_id`),
CONSTRAINT `Views_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `User` (`id`) ON
UPDATE CASCADE ON DELETE CASCADE
)
COLLATE='utf8_swedish_ci'
ENGINE=InnoDB;

I think you need to revise your logic. It makes no sense to Insert a row only to delete another row. Why not just update the Group_ID field in the duplicate row to what is being inserted? Below is a rough idea of how I would go about it.

N.b. I haven't done much work with MySQL and cannot get the below to run on SQLFiddle, but based on the MySQL docs I can't work out why. Perhaps someone more versed in MySQL can correct me?

SET @User_ID = 1;
SET @db = 'db_a';
SET @Field = 'Field';
SET @Display = 1;
SET @Search = 1;
SET @Group_ID = 1;

IF EXISTS
    (   SELECT  1
        FROM    Views
        WHERE   User_ID = @User_ID
        AND     DB = @DB
        AND     Field = @Field
        AND     Group_ID IS NOT NULL
    ) 
    THEN
        UPDATE  Views
        SET     Group_ID = @Group_ID,
                Display = @Display,
                Search = @Search
        WHERE   User_ID = @User_ID
        AND     DB = @DB
        AND     Field = @Field
        AND     Group_ID IS NOT NULL
ELSE
        INSERT INTO Views (User_ID, DB, Field, Display, Search, Group_ID)
        VALUES (@User_ID, @DB, @Field, @Display, @Search, @Group_ID)
END IF;

Alternatively (and my preferred solution), add a Timestamp field to your table and create a view as follows:

SELECT  v.User_ID, v.DB, v.Field, v.Display, v.Search, v.Group_ID
FROM    Views v
        INNER JOIN
        (   SELECT  User_ID, DB, Field, MAX(CreatedDate) AS CreatedDate
            FROM    Views
            WHERE   Group_ID IS NOT NULL
            GROUP BY User_ID, DB, Field
        ) MaxView
            ON MaxView.User_ID = v.User_ID
            AND MaxView.DB = v.DB
            AND MaxView.Field = v.Field
            AND MaxView.CreatedDate = v.CreatedDate
WHERE    v.Group_ID IS NOT NULL
UNION ALL
SELECT  v.User_ID, v.DB, v.Field, v.Display, v.Search, v.Group_ID
FROM    Views v
WHERE   v.Group_ID IS NULL

This would allow you to track changes to your data properly, without compromising the need to be able to view unique records.

delete group_id from Views where group_id != 'NUll'

Your question is not very good to understand, so I'm not sure this is what you want:

DELETE FROM Views WHERE # delete from the table views
  group_id IS NOT NULL AND  # first condition delete only rows with not null group_id
  (SELECT count(*) as tot FROM Views GROUP BY group_id) = 1 # second condition count the difference in group id

If that's not what you want, please update your question with more details...