我有一个MySql表,每天填充价格值。 即使价格没有变化,它也会每天记录一个条目。 我想删除一些重复太多的行。 我希望在价格变动之前保留第一个价格和最后价格。

例1)

   id name     price date
    1 Product1 $6 13/07/2017
    2 Product1 $6 14/07/2017
    3 Product1 $6 15/07/2017
    4 Product1 $7 16/07/2017
    5 Product1 $6 17/07/2017
    6 Product1 $6 18/07/2017
    7 Product1 $6 19/07/2017

从该列表中删除ID为2和6的记录,结果如下:

   id name     price date
    1 Product1 $6 13/07/2017
    3 Product1 $6 15/07/2017
    4 Product1 $7 16/07/2017
    5 Product1 $6 17/07/2017
    7 Product1 $6 19/07/2017

例2)

   id name     price date
    1 Product1 $6 13/07/2017
    2 Product1 $6 14/07/2017
    3 Product1 $6 15/07/2017
    4 Product1 $6 16/07/2017
    5 Product1 $6 17/07/2017
    6 Product1 $6 18/07/2017
    7 Product1 $6 19/07/2017

这里没有价格变化,所以我可以删除2到6的所有记录:

   id name     price date
    1 Product1 $6 13/07/2017
    7 Product1 $6 19/07/2017

Id不应该是一个增量,并且日期不会每天更新。

#1楼 票数:5

您可以使用一些创造性的自连接逻辑来执行此操作。

想想表中的三个假设行。

  • 你要保留的行。
  • 第b行具有相同的产品名称和价格,以及日期后1天的日期。 你想删除它。
  • 行c具有相同的产品名称和价格,以及b之后的第1天的日期。 你想保留这个。

因此,如果您可以执行自联接以匹配这三行,则删除行b。

DELETE b FROM MyTable AS a 
JOIN MyTable AS b ON a.name=b.name AND a.price=b.price AND a.date=b.date + INTERVAL 1 DAY 
JOIN MyTable AS c ON b.name=c.name AND b.price=c.price AND b.date=c.date + INTERVAL 1 DAY;

即使有多行符合行b的条件,这仍然有效。 它将删除第一个,然后继续删除也符合条件的后续行。

如果您使用DATE数据类型并将日期存储为“YYYY-MM-DD”而不是“DD-MM-YYYY”,则此方法有效。 无论如何你应该这样做。

#2楼 票数:3

您希望删除产品名称和价格与日期加/减一天的行相同的行。

DELETE row_mid
FROM 
  record_table AS row_mid
  JOIN record_table AS row_prev
  JOIN record_table AS row_next
WHERE
  row_mid.name = row_prev.name 
  AND row_mid.price = row_prev.price
  AND row_mid.date = DATE_SUB(row_prev.date, INTERVAL 1 DAY)
  AND row_mid.name = row_next.name
  AND row_mid.price = row_next.price
  AND row_mid.date = DATE_ADD(row_next.date, INTERVAL 1 DAY);

#3楼 票数:3

你的MySQL是否足以支持CTE? 这是我在日期安排中看到的一个非常有趣的问题。 代码看起来总是很尴尬。 要在没有删除的情况下检查结果,可以使用select和delete切换注释标记并注释掉t。[Name]为空行。

WITH

cte AS  (
        SELECT a.ID
            , a.[Name]
            , a.[Date]
            , a.Price
            , NextDate = max(npc.[Date])    -- Next Price change
            , PrevDate = max(lpc.[Date])    -- Next Price change
        FROM    yourTable as a  -- Base Table
            LEFT JOIN
                yourTable as npc    -- Looking for Next Price Change
            ON a.[Name] = npc.[Name]
                and a.[Date] < npc.[Date]
                and a.Price <> npc.Price
            LEFT JOIN
                yourTable as lpc    -- Looking for Last Price Change
            ON a.[Name] = lpc.[Name]
                and a.[Date] > lpc.[Date]
                and a.Price <> lpc.Price
        GROUP BY a.ID, a.[Name], a.[Date], a.Price
    ) 

----SELECT f.*, [Check] = CASE WHEN t.[Name] is null THEN 'DELETE' ELSE '' END
DELETE f
FROM 
        yourTable as f
    LEFT JOIN
        (
            SELECT [Name], [GoodDate] = Max([Date])
            FROM cte
            GROUP BY [Name], PrevDate
            UNION
            SELECT [Name], [GoodDate] = Min([Date])
            FROM cte
            GROUP BY [Name], PrevDate
            UNION
            SELECT [Name], [GoodDate] = Max([Date])
            FROM cte
            GROUP BY [Name], NextDate
            UNION
            SELECT [Name], [GoodDate] = Min([Date])
            FROM cte
            GROUP BY [Name], NextDate
        ) as t
    ON t.[Name] = f.[Name] and t.[GoodDate] = f.[Date]
WHERE t.[Name] is null
--ORDER BY f.[Name], f.[Date]

#4楼 票数:3

您可以检测prev Idnext Id ,然后选择要删除的行:

SELECT * 
FROM 
  (SELECT 
      *,
      (SELECT next_id.id 
       FROM a next_id 
       WHERE next_id.id > current.id 
       ORDER BY next_id.id ASC LIMIT 1) as next_id,
      (SELECT prev_id.id 
       FROM a prev_id 
       WHERE prev_id.id < current.id 
       ORDER BY prev_id.id DESC LIMIT 1) as prev_id 
   FROM a current) t
WHERE 
   EXISTS (SELECT 1 
           FROM a next 
           WHERE next.name = t.name AND t.price = next.price AND next.id=t.next_id) 
   AND
   EXISTS (SELECT 1 
           FROM a prev 
           WHERE prev.name = t.name AND t.price = prev.price AND prev.id=t.prev_id)

我在两个示例中测试了这些查询。 演示

更新 如果Id列不是唯一的,那么逻辑必须从prev Id + next Id更正为prev Date + next Date 无论如何,一般概念将保持不变。 查询将如下所示:

SELECT * 
FROM 
  (SELECT 
      *,
      (SELECT next_date.date 
       FROM a next_date 
       WHERE next_date.date > current.date AND next_date.name = current.name
       ORDER BY next_date.date ASC LIMIT 1) as next_date,
      (SELECT prev_date.date
       FROM a prev_date 
       WHERE prev_date.date < current.date AND prev_date.name = current.name
       ORDER BY prev_date.date DESC LIMIT 1) as prev_date
   FROM a current) t
WHERE 
   EXISTS (SELECT 1 
           FROM a next 
           WHERE next.name = t.name AND t.price = next.price AND next.date=t.next_date) 
   AND
   EXISTS (SELECT 1 
           FROM a prev 
           WHERE prev.name = t.name AND t.price = prev.price AND prev.date=t.prev_date)

演示第二次查询。

#5楼 票数:2

您的所有数据都会被重复,您想要保留一个吗? 你的解释很混乱。

您可以以相同的价格保存最旧的数据并删除其他数据:

with Ranked as (
select  name, price, date,
    dense_rank() 
    over (partition by name, price, date 
order by date desc) as DupeCount
from    Your_table P
)
delete  R
from    Ranked R
where   R.DupeCount <> 1

#6楼 票数:2

好吧,我无法为您的场景编写确切的代码,但您可以编写一个Function \\ Procedure并遵循此伪代码

r = allrows
tobeDeleted = []
unique = []
for (var i=0;i<rows.length; i++){
    unique.push(rows[i]->id);
    dd = true;
    while (dd){
        if ((rows[i]->price == rows[i+1]->price) AND (rows[i]->name == rows[i+1]->price)){
            tobeDeleted.push(rows[i]->id);
            i++;
        }else{
            dd= false;
        }
    }
}

//tobeDeleted contains ids of rows to be deleted
//

#7楼 票数:2

尝试以下查询,希望它可以帮助您。

(我没有mysql,我试图将语法转换为我的sql--所以如果有任何语法错误我很抱歉。)

(我已经在sqlserver上测试了它的随机日期和不同的产品,它运行良好并得到你想要的结果)

/* get the data grouped by name with NewField continousDate to create continous dates for every product depends on the order of date
then save it to temporary table called tempWithContinousDate*/

CREATE TEMPORARY Table tempWithContinousDate Table  (id INT,name varchar(50),price DECIMAL(12,2),date DATE,continousDate DATE)

insert into tempWithContinousDate(id,name,price,date,continousDate)
select id,name,price,date,Date_Add(minimumDate,INTERVAL rn DAY)ContinousDate
from(
select t1.id,t1.name,t1.price,t1.date,min(t2.Date)minimumDate,count(*) rn
          from 
             (select id,name,price,date from yourTable) t1
          inner join 
            (select id,name,price,date from yourTable) t2 
          on t1.name=t2.name and t1.date>=t2.date
 group by t1.id,t1.name,t1.price,t1.date
 ) t




/* get the data grouped by name and price with NewField GroupDate to group every continous dates 
then save it to temporary table called tempData*/
CREATE TEMPORARY Table tempData (id INT,name varchar(50),price DECIMAL(12,2),date DATE,groupDate DATE)

insert into tempData(id,name,price,date,groupDate)
select id,name,price,date,DATE_SUB(continousDate, INTERVAL rowNumber DAY) groupDate
from(
select t1.id,t1.name,t1.price,t1.date,t1.continousDate,count(*) rowNumber
          from 
             (select id,name,price,date,continousDate from tempWithContinousDate) t1
          inner join 
            (select id,name,price,date,continousDate from tempWithContinousDate) t2 
          on t1.name=t2.name and t1.price=t2.price and t1.date>=t2.date
 group by t1.id,t1.name,t1.price,t1.date,t1.continousDate
 ) t



 /*select * from yourTable where id  in*/
 delete from yourTable where id not in
(select id from 
 (

/* query to order every continous data asscending using the date field */
select firstData.id,firstData.name,firstData.price,firstData.date,count(*) rn 
from  tempData firstData
left join  tempData secondData
on firstData.name=secondData.name and firstData.price=secondData.price and firstData.groupDate=secondData.groupDate
and firstData.date>=secondData.date
group by firstData.id,firstData.name,firstData.price,firstData.date


/* query to order every continous data  Descending using the date field */
union all
select firstData.id,firstData.name,firstData.price,firstData.date,count(*) rn 
from  tempData firstData
left join  tempData secondData
on firstData.name=secondData.name and firstData.price=secondData.price and firstData.groupDate=secondData.groupDate
and firstData.date<=secondData.date
group by firstData.id,firstData.name,firstData.price,firstData.date

 )allData where rn=1  

)       

#8楼 票数:1

您可以使用下面的代码。 如果有效,请告诉我。

DELETE FROM record_table
WHERE id NOT IN (
    (SELECT MIN(id) FROM record_table GROUP BY name, price),
    (SELECT MAX(id) FROM record_table GROUP BY name, price)
)

#9楼 票数:1

您可以使用EXISTS

DELETE FROM test t1
WHERE EXISTS
(
  SELECT * 
  FROM test t2 
  WHERE t1.name = t2.name AND t1.price = t2.price AND t1.day = DATE_SUB(t2.DAY, INTERVAL 1 DAY)
) AND
EXISTS(
  SELECT * 
  FROM test t3 
  WHERE t1.name = t3.name AND t1.price = t3.price AND t1.day = DATE_ADD(t3.DAY, INTERVAL 1 DAY)
)

IN构建来解决您的问题

DELETE FROM test t1
WHERE t1.day IN (
  SELECT DATE_SUB(t2.day, INTERVAL 1 DAY)
  FROM test t2 
  WHERE t1.NAME = t2.NAME AND t1.price = t2.price
) AND t1.day IN (
  SELECT DATE_ADD(t3.day, INTERVAL 1 DAY) 
  FROM test t3 
  WHERE t1.NAME = t3.NAME AND t1.price = t3.price
)

sqlfiddle演示

#10楼 票数:1

您可以使用以下逻辑:

  1. 按价格排名
  2. 按ID,名称,价格分组
  3. 获得最短的约会
  4. 得到最大日期

继查询和小提琴示例之后:

SET @prev_value = NULL;
SET @rank_count = 0;

select distinct
  `name`,
  `price`,
  `date`
from 
(
  (
  select 
    id,
    name,
    price,
    CASE
      WHEN @prev_value = price THEN @rank_count
      WHEN @prev_value := price THEN @rank_count := @rank_count + 1
    END AS rank,
    min(`date`) as `date`
  from 
    `prices`
   group by 
     `name`, 
     `price`, 
     `rank`
   )
   union distinct
   (
   select 
    id,
    name,
    price,
    CASE
      WHEN @prev_value = price THEN @rank_count
      WHEN @prev_value := price THEN @rank_count := @rank_count + 1
    END AS rank,
    max(`date`) as `date`
  from 
    `prices`
   group by 
     `name`, 
     `price`, 
     `rank`
  )
  order by `id`, `date`
) as `result`

sqlfiddle

#11楼 票数:1

我们必须问自己,我们何时必须删除记录?

答:可以删除记录,

  • 如果存在具有相同名称,具有相同价格和更早日期的另一记录,而没有具有相同名称的记录,则两个日期之间具有另一个价格。

  • 如果存在具有相同名称,具有相同价格和更晚日期的另一条记录,而没有具有相同名称的记录,则两个日期之间具有另一个价格。

将两个需求放入SQL会导致以下结果:

DELETE FROM PriceTable t
WHERE 
  EXISTS ( SELECT *
           FROM PriceTable tmp1 
           WHERE t.name  = tmp1.name  AND 
                 t.price = tmp1.price AND 
                 t.date  > tmp1.date  AND
                 NOT EXISTS (SELECT * 
                             FROM PriceTable tmp2
                             WHERE t.name    = tmp2.name  AND 
                                   t.price  != tmp2.price AND 
                                   t.date    > tmp2.date  AND 
                                   tmp1.date < tmp2.date 
                            )
         )
  AND
  EXISTS ( SELECT *
           FROM PriceTable tmp1 
           WHERE t.name  = tmp1.name  AND 
                 t.price = tmp1.price AND 
                 t.date  < tmp1.date  AND
                 NOT EXISTS (SELECT * 
                             FROM PriceTable tmp2
                             WHERE t.name    = tmp2.name  AND 
                                   t.price  != tmp2.price AND 
                                   t.date    < tmp2.date  AND 
                                   tmp1.date > tmp2.date 
                            ) 
         );

#12楼 票数:1

编辑:经过进一步考虑后,似乎无法用用户定义的变量技巧来解决这个问题(注意使用这些的其他解决方案)。 虽然我认为以下解决方案“最有可能在99%的时间内工作”,但MySQL并不保证变量评估的顺序: 链接1链接2

原始答案:

(我的假设是products.name被定义为NOT NULL ,而products.idproducts.price都不是负数[如果处理否定也可以提供一个简单的补丁])。

查询:

SET
    @one_prior_id := NULL,
    @one_prior_price := NULL,
    @one_prior_name := NULL,
    @two_prior_id := NULL,
    @two_prior_price := NULL,
    @two_prior_name := NULL
;

SELECT @two_prior_id AS id_to_delete
FROM (
    SELECT *
    FROM products
    ORDER BY name, date
) AS t
WHERE IF(
    (
        (name  = @one_prior_name)
        AND
        (name  = @two_prior_name)
        AND
        (price = @one_prior_price)
        AND
        (price = @two_prior_price)
    ), (
        GREATEST(
            1,
            IFNULL(@two_prior_id := @one_prior_id, 0),
            IFNULL(@two_prior_price := @one_prior_price, 0),
            LENGTH(IFNULL(@two_prior_name := @one_prior_name, 0)),
            IFNULL(@one_prior_id := id, 0),
            IFNULL(@one_prior_price := price, 0),
            LENGTH(IFNULL(@one_prior_name := name, 0))
        )
    ), (
        LEAST(
            0,
            IFNULL(@two_prior_id := @one_prior_id, 0),
            IFNULL(@two_prior_price := @one_prior_price, 0),
            LENGTH(IFNULL(@two_prior_name := @one_prior_name, 0)),
            IFNULL(@one_prior_id := id, 0),
            IFNULL(@one_prior_price := price, 0),
            LENGTH(IFNULL(@one_prior_name := name, 0))
        )
    )
)

查询返回,基于您的“示例1:”

+--------------+
| id_to_delete |
+--------------+
|            2 |
|            6 |
+--------------+

查询返回,基于您的“示例2:”

+--------------+
| id_to_delete |
+--------------+
|            2 |
|            3 |
|            4 |
|            5 |
|            6 |
+--------------+

查询的工作原理:

  • 通过ORDER BY对products表进行简单的“分区”

  • 循环遍历有序结果集,跟踪2组变量:第一组用于保存“一个先前”行的价格和名称(“一个先前”行直接位于当前行之上),第二个变量集合为保持'前两行'('前两行'直接位于'前一行'行之上)。

  • GREATESTLEAST是相同的,除了前者返回一个值,该值将为IF评估为true,后者将评估为false。 这些函数的真正意义在于更新循环变量。

  • 对有关子查询中使用变量更新的详细信息。

实际的DELETE:

SET
    @one_prior_id := NULL,
    @one_prior_price := NULL,
    @one_prior_name := NULL,
    @two_prior_id := NULL,
    @two_prior_price := NULL,
    @two_prior_name := NULL
;

DELETE FROM products WHERE id IN (
    SELECT * FROM (
        SELECT @two_prior_id AS id_to_delete
        FROM (
            SELECT *
            FROM products
            ORDER BY name, date
        ) AS t1
        WHERE IF(
            (
                (name  = @one_prior_name)
                AND
                (name  = @two_prior_name)
                AND
                (price = @one_prior_price)
                AND
                (price = @two_prior_price)
            ), (
                GREATEST(
                    1,
                    IFNULL(@two_prior_id := @one_prior_id, 0),
                    IFNULL(@two_prior_price := @one_prior_price, 0),
                    LENGTH(IFNULL(@two_prior_name := @one_prior_name, 0)),
                    IFNULL(@one_prior_id := id, 0),
                    IFNULL(@one_prior_price := price, 0),
                    LENGTH(IFNULL(@one_prior_name := name, 0))
                )
            ), (
                LEAST(
                    0,
                    IFNULL(@two_prior_id := @one_prior_id, 0),
                    IFNULL(@two_prior_price := @one_prior_price, 0),
                    LENGTH(IFNULL(@two_prior_name := @one_prior_name, 0)),
                    IFNULL(@one_prior_id := id, 0),
                    IFNULL(@one_prior_price := price, 0),
                    LENGTH(IFNULL(@one_prior_name := name, 0))
                )
            )
        )
    ) AS t2
)

重要的提示

看看上面的删除查询如何做2个内部选择? 确保包含此内容,否则您将无意中删除最后一行! 尝试在没有SELECT (...) AS t2情况下执行,看看我的意思。

#13楼 票数:1 已采纳

这是我为这个问题提交的第二个答案,但我想这次我终于得到了它:

DELETE FROM products WHERE id IN (
    SELECT id_to_delete
    FROM (
        SELECT
            t0.id AS id_to_delete,
            t0.price,
            (
                SELECT t1.price
                FROM products AS t1
                WHERE (t0.date < t1.date)
                    AND (t0.name = t1.name)
                ORDER BY t1.date ASC
                LIMIT 1
            ) AS next_price,
            (
                SELECT t2.price
                FROM products AS t2
                WHERE (t0.date > t2.date)
                    AND (t0.name = t2.name)
                ORDER BY t2.date DESC
                LIMIT 1
            ) AS prev_price
        FROM products AS t0
        HAVING (price = next_price) AND (price = prev_price)
    ) AS t
)

这是@vadim_hr答案的修改版本。

编辑:下面是一个不同的查询,过滤JOIN而不是子查询。 对于大型数据集, JOIN可能比前一个查询(上图)更快,但我会将性能测试留给您。

http://sqlfiddle.com/#!9/ee0655/8

SELECT M.id as id_to_delete
FROM
(
    SELECT
        *,
        (@j := @j + 1) AS j
    FROM
    (SELECT * FROM products ORDER BY name ASC, date ASC) AS mmm
    JOIN
    (SELECT @j := 1) AS mm
) AS M     -- the middle table
JOIN
(
    SELECT
        *,
        (@i := @i + 1) AS i
    FROM
    (SELECT * FROM products ORDER BY name ASC, date ASC) AS lll
    JOIN
    (SELECT @i := 0) AS ll
) AS L     -- the left table
ON M.j = L.i
    AND M.name = L.name
    AND M.price = L.price
JOIN
(
    SELECT
        *,
        (@k := @k + 1) AS k
    FROM
    (SELECT * FROM products ORDER BY name ASC, date ASC) AS rrr
    JOIN
    (SELECT @k := 2) AS rr
) AS R     -- the right table
ON M.j = R.k
    AND M.name = R.name
    AND M.price = R.price

两个查询都完成相同的结束,并且它们都假设每个namedate行是唯一的(如下面的注释中所述)。

  ask by Ahsan Mukhtar translate from so

未解决问题?本站智能推荐:

1回复

DATABASE-特权,使用户能够删除数据库中的表,但不能删除数据库中的表

我正在建立一个数据库,其中用户有权访问数据库。 问题是我希望该用户具有创建和删除表的权限,但是他不应该具有创建和删除数据库(甚至是分配给他的数据库)的能力。 我在MariaDB和MySQL的文档中读到,DROP特权适用于数据库,表和视图: https://mariadb.com/kb/zh
2回复

如何删除数据库中MySQL表中的相关数据?

我确信这是一个非常基本的问题,但是我茫然不知所措,最近开始使用MySQL。 我已经修改,创建了数据库,用户,表,向表中添加和修改了条目,但是现在我认为我需要在此处使用Join,但是我不确定。 在同一个数据库中,我有两个表。 任务表有两列感兴趣的用户和密钥ID。 活动表中有一列有趣的任
1回复

关于从mysql中的表中删除数据库数据

我是mysql新手。 我的要求是我有一个数据库“样本”,并且其中有20个表以及一些样本数据。 我想从该数据库的所有表中删除所有数据,而不删除表或重新创建它们 因此,请为我提供解决方案。 问候成都市。
1回复

使用选择输入删除数据库中的对象后,尝试获取“中的非对象的属性”

我可以选择并单击“ Slett”将其从数据库中删除 删除后休息没有出现 当我再次更新页面时,他们会出现...... 因为错误我得到“注意:尝试在删除后获取非对象的属性” 我正在使用PHP,一切正常,但我删除后选择输入中没有选项。 这是我的代码,在Stackoverf
1回复

SQL:即时创建/删除数据库和表的副作用

我需要通过在mysql(客户要求:P)上创建包装器来模拟sql,因此我的应用程序需要在运行时创建/删除表(可能还有数据库)。 这样的创建/删除操作的频率不会很高。 我不是数据库专家,但我相信这种操作可能会长期产生一些副作用。 是否建议继续进行这些数据库的创建/删除操作,以及可能遇到
1回复

用于删除数据库中所选行的表单:始终显示确认

我有一个表单从我的SQL数据库中删除一行。 我昨天运行了它但由于某种原因它不会成功删除任何东西,只需返回确认消息。 我知道我的所有登录/连接细节都是正确的。 请告诉我这个脚本是否有错误。 PHP 形成
1回复

从表中删除数据时出现SQL错误-删除的目标和源[重复]

这个问题已经在这里有了答案: MySQL错误1093-无法在FROM子句 15中 指定要更新的目标表 我正在尝试执行此查询。 删除所有小于account表中所有帐户平均值的account 。 但是,我收到此错误: #1093 - Table 'account
4回复

删除数据库中的重复项

我有一个看起来像这样的数据库: 我想删除pID相等bsID相等upDatum相等的每一行。 到目前为止,我已经知道了: DELETE FROM twh_uren_prognose WHERE EXISTS (SELECT b.* FROM twh_uren_prognose b W