MySQL: инициализировать сводную таблицу с заполнителями для несуществующих данных - PullRequest
0 голосов
/ 18 мая 2009

Я постараюсь дать это как можно более обобщенно, чтобы его можно было многократно использовать.

Я управляю сайтом с довольно большой базой данных MySQL, для которой требуется инициализация некоторых сводных / сводных таблиц. Для примера, скажем, это футбольная статистика. Поскольку я работаю с несколькими футбольными лигами в одной базе данных, многие из них играют в игры разной длины - например, внутренние футбольные лиги играют четыре четверти, а большинство открытых лиг играют пополам.

У меня есть три таблицы, важные для этого упражнения. Я отредактировал все поля, которые я не считаю существенными для ответа, который ищу.

GAME
`game`.id
`game`.home_team_id
`game`.away_team_id
`game`.number_of_periods

GOAL 
// Records for each goal scored in the game   
`goal`.id
`goal`.game_id
`goal`.team_id
`goal`.period_number
`goal`.player_id
`goal`.assist_player_id

PERIOD_SUMMARY
`period`.id
`period`.game_id
`period`.team_id
`period`.number
`period`.goals_scored    

В конечном итоге я должен иметь записи за КАЖДЫЙ период, сыгранные в сводной таблице периодов, независимо от того, был ли забит гол или нет. Эту таблицу необходимо инициализировать только один раз, поскольку довольно просто добавить соответствующие заполненные нулями записи с помощью триггера при создании игры и запустить запросы на вставку / обновление для обновления таблицы period_summary.

Мне также довольно легко сгруппировать все цели и инициализировать сводную таблицу периодов с помощью SUM (), в связи с чем у меня возникли некоторые затруднения в поиске эффективного способа «заполнить» любые периоды, которые не гол забит с 0.

То, что я пытаюсь выяснить, так это то, что проще / эффективнее:

  1. Запишите триггер и предварительно заполните всю таблицу period_summary значениями, заполненными 0, а затем выполните уже известный мне запрос, чтобы обновить соответствующие записи для периодов, в которых были забиты цели.
  2. Используйте какой-то другой метод (возможно, временную хранимую процедуру?), Который будет заполнять только 0 записей, если в таблице целей нет совпадений.

Ответы [ 3 ]

3 голосов
/ 14 августа 2009

У вас уже есть заполнитель. «Заполнитель для unknown data» в SQL является нулевым.

Вам не нужно ничего предварительно заполнять: либо у вас есть строка с несколькими столбцами, имеющими неизвестное значение (null), либо у вас нет строки вообще, так что при выполнении внешнего соединения получится строка, которая все ноль. В любом случае, данные атрибута (по существу, поля не-id) будут нулевыми.

И агрегат sum() будет игнорировать нули.

Итак, допустим, что у вас do есть строка для игры (поскольку она запланирована заранее), но нет соответствующих строк для ее периодов (поскольку они еще не были сыграны). Затем вы создаете игру с внешним соединением для периода (внешнюю, так что вы включаете как игры с , так и игры без , данные периода):

select a.*, sum(b.goals_scored)
from game a left outer join period b on (b.game_id = a.id)
group by a.id;

Показывает общее количество голов (для обеих команд) по играм; для игр без периодов вы получаете ноль (что означает в SQL «мы (пока) не знаем»)

В этом запросе отображаются только общие цели для завершенных игр и игр в процессе (игры, в которых был сыгран хотя бы один период) :

select a.*, sum(b.goals_scored)
from game a join period b on (b.game_id = a.id)
group by a.id;

Это представление отфильтровывает незавершенные игры (при условии, что вы всегда добавляете ранние периоды раньше, чем более поздние):

create view complete_games as
select a.* from games a
where exists (select * from period b 
where b.game_id = a.id and b.number = a.number_of_periods)

Используя это представление, мы можем затем суммировать только завершенные игры:

select a.*, sum(b.goals_scored)
from complete_games a join period b on (b.game_id = a.id)
group by a.id;

Таким образом, нет необходимости предварительно заполнять, нет необходимости в триггере, что наиболее важно, нет необходимости добавлять ложные данные (требуются нулевые цели, когда фактически период еще не был сыгран), нет необходимости обновлять правильные данные , Просто введите период, когда у вас есть данные для этого.

0 голосов
/ 15 августа 2009

Знаете ли вы, что вы можете установить значение по умолчанию для столбца? С ключевым словом по умолчанию.

например:.

CREATE TABLE Person ( возраст INT DEFAULT 0, имя VARCHAR (35) ПО УМОЛЧАНИЮ 'Боб' )

Значением по умолчанию будет то, что вы хотите (например, 0) вместо нуля.

Не все решает, но поможет.

0 голосов
/ 14 августа 2009

ISTM, что вариант 1 явно проще: вы уже знаете, как увеличить счетчик ударов, если можете доверять, что счетчик уже есть. Предположим, что вы выбрали вариант 2: не только сложнее заполнить недостающие нули (я предполагаю, что это должно произойти в конце периода), но вам также нужно найти способ запустить счетчик с 1, если предыдущей записи нет, и забит первый гол.

Что касается эффективности использования пространства: в конечном счете, вам в любом случае потребуется одинаковое пространство на диске. Было бы немного эффективнее заполнять нули только в конце периода, но, несомненно, пространство, которое займут завершенные периоды, в любом случае больше, чем пространство для периодов выполнения.

Что касается эффективности вставки / обновления: вам нужно будет выполнить поиск, когда цель будет забита в любом случае, потому что может уже быть ненулевой счетчик. Таким образом, вам нужно создать индекс, который позволяет эффективно искать по игре, команде и периоду. Учитывая, что запрос, который всегда выполняет обновление, короче, есть большая вероятность, что он также более эффективен.

...