mysql - 基于其他行的UPDATE行

时间:2011-02-05 17:08:09

标签: sql mysql database

我希望根据基于其他行的特定条件更新某些行。让我们说这个表看起来像这样:

COLUMNS:   time              type     genre    doubles     triples
ROW 1:    2010.06.21 12:00    1        1        0            0
ROW 2:    2010.06.21 12:00    1        2        0            0
ROW 3:    2010.06.21 12:00    1        1        0            0
ROW 4:    2010.06.21 12:00    2        3        0            0
ROW 5:    2010.06.22 12:00    2        2        0            0
ROW 6:    2010.06.22 12:00    2        3        0            0
ROW 7:    2010.06.22 12:00    1        1        0            0

我希望根据以下规则更新doublestriples列:

1)仅查看更新行之间time=timetype=type的行(例如,行1,2,3和行5和6)。

2)接下来计算这些行之间的不同genre的#,如果有两个不同的genres,则将doubles列更改为1,或者如果有三个则将triples列更改为1.例如,在上表中,行1,2,3将具有doubles=1,因为在这三行之间有两种不同的流派。第5行和第6行也会有doubles=1,因为行之间还有两种不同的类型。 Doubles可以= 1而triples可以= 1但不能同时使用。

现在,我可以很容易地根据这些规则编写一些PHP,但我想知道是否有办法在mysql中完成所有操作?看起来我总是对从SQL语句中可以做的数量感到惊讶。

可能类似(doublestriples列的两个不同陈述):

双打 - UPDATE myTable SET (doubles=1) WHERE time=time AND type=type ...但是,您将如何解释上面的规则#2(计算具有唯一类型的行数)。

这在mysql中是可行的还是PHP才是正确的方法?

提前致谢

2 个答案:

答案 0 :(得分:1)

可以使用子选择和CASE表达式,或者通过将计数与列的计数进行比较,但由于MySQL不允许您选择表,因此很难这是在子选择中更新。

你可以在一个选择中轻松地完成它(我给表中的'录音'的名称,因为你没有指定它;在SQL中提供样本而不是预先格式化的文本总是有用的):

SELECT r0.id, r0.`time`, r0.`type`, r0.`genre`,
     COUNT(DISTINCT r1.genre) = 2 AS doubles,
     COUNT(DISTINCT r1.genre) = 3 AS triples
  FROM recordings AS r0
    JOIN recordings AS r1 ON r0.`time`=r1.`time` AND r0.`type`=r1.`type`
  GROUP BY r0.`id`, r0.`time`, r0.`type`, r0.`genre`

然后,您可以将此作为stored procedureview的基础:

ALTER TABLE recordings DROP COLUMN doubles;
ALTER TABLE recordings DROP COLUMN triples;
ALTER TABLE recordings ADD id INT PRIMARY KEY AUTO_INCREMENT;

CREATE VIEW recording_genre_count AS
SELECT r0.id, r0.`time`, r0.`type`, r0.`genre`,
     CASE COUNT(DISTINCT r1.genre) WHEN 2 THEN 1 ELSE 0 END AS doubles,
     CASE COUNT(DISTINCT r1.genre) WHEN 3 THEN 1 ELSE 0 END AS triples
  FROM recordings AS r0
    JOIN recordings AS r1 ON r0.`time`=r1.`time` AND r0.`type`=r1.`type`
  GROUP BY r0.`id`, r0.`time`, r0.`type`, r0.`genre`;
  --Since the columns of recordings are functionally dependent on recordings.id,
  --you could use just "GROUP BY r0.id", but the above will work on other
  -- DBMSs

如果群组频繁更改,则视图是更好的选择。它还确保数据consistency。如果必须运行查询以更新doublestriples列,则在插入行后,数据库通常会处于不一致状态(triggers可能对此有所帮助,但是在UPDATE中进行子选择,触发器在从正在更新的表中进行选择时出现问题。视图和查询也更容易允许其他列(例如quadruples)而不是存储过程。

答案 1 :(得分:1)

当然,您可以在一个查询中执行此操作。使用此样本表:

create table duotri (time varchar(100), type int, genre int, doubles int, triples int);
insert duotri values
('2010.06.21 12:00'    ,1        ,1        ,0            ,0),
('2010.06.21 12:00'    ,1        ,2        ,0            ,0),
('2010.06.21 12:00'    ,1        ,1        ,0            ,0),
('2010.06.21 12:00'    ,2        ,3        ,0            ,0),
('2010.06.22 12:00'    ,2        ,2        ,0            ,0),
('2010.06.22 12:00'    ,2        ,3        ,0            ,0),
('2010.06.22 12:00'    ,1        ,1        ,0            ,0);

update语句应该加入GROUPed表单以获得双打和三元组。

update duotri t1
inner join (
    select time, type,
     case when count(distinct genre) = 2 then 1 else 0 end doubles,
     case when count(distinct genre) = 3 then 1 else 0 end triples
    from duotri
    group by time, type) t2
   on t1.time=t2.time and t1.type=t2.type
set t1.doubles=t2.doubles, t1.triples = t2.triples;