Я хочу обновить определенные строки на основе определенных критериев, основанных на других строках. Допустим, что таблица выглядит так:
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
Я хочу обновить столбцы doubles
и triples
на основе следующих правил:
1) Посмотрите только на обновление строк, где time=time
и type=type
между строками (например, строки 1,2,3 и строки 5 и 6).
2) Затем подсчитайте # из разных genre
между этими строками, и если есть два разных genres
, измените столбец doubles
на 1, или если их три, измените столбец triples
на 1 SO, например, в таблице выше строк 1,2,3 будет doubles=1
, потому что между тремя строками есть два разных жанра. Строки 5 и 6 также имели бы doubles=1
, потому что между строк снова появляются два разных жанра. doubles
can = 1 и triples
can = 1, но не оба.
Теперь я могу написать некоторые PHP на основе этих правил довольно легко, я думаю, но мне интересно, есть ли способ сделать все это в mysql? Похоже, я всегда удивляюсь тому, какую сумму вы можете сделать из инструкции SQL.
Может быть, что-то вроде (два разных оператора для столбца doubles
и triples
):
Doubles - UPDATE myTable SET (doubles=1) WHERE time=time AND type=type
... но тогда как бы вы определили правило № 2 выше (подсчет количества строк с уникальными жанрами).
Возможно ли это в mysql или PHP - это правильный путь?
Заранее спасибо
Конечно, вы можете сделать это в одном запросе. Использование этой таблицы образцов:
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);
Оператор обновления должен присоединиться к форме GROUP, чтобы получить удвоения и тройки.
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;
Это может быть возможно с помощью подвыборов и выражения CASE
или путем сравнения количества отсчетов с подсчетом для столбца, но это будет сложно из-за того, что MySQL не позволяет вам выбрать таблицу, которая является обновлен в подзапросе.
Вы можете сделать это легко в select (я даю таблице имя "записей", так как вы не указали ее; предоставление образцов в 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`
Затем вы можете использовать это как основу для хранимой процедуры или view:
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. Если вам нужно запустить запрос для обновления столбцов doubles
и triples
, БД будет часто находиться в несогласованном состоянии сразу после вставления строк (triggers может помочь с этим, но, как и подвыборки в UPDATE
s, триггеры имеют проблемы с выбором из обновляемой таблицы). Представления и запросы также более легко позволяют добавлять дополнительные столбцы (например, quadruples
), чем хранимые процедуры.