Суммирование поля из всех таблиц в базе данных - PullRequest
0 голосов
/ 06 августа 2009

У меня есть база данных MySQL под названием «bookfeather». Содержит 56 таблиц. Каждая таблица имеет следующую структуру:

id site votes_up votes_down

Значение "site" - это название книги. Значение для "voice_up" является целым числом. Иногда уникальное значение для «сайта» появляется в нескольких таблицах.

Для каждого уникального значения "site" во всей базе данных я хотел бы суммировать "voice_up" из всех 56 таблиц. Затем я хотел бы напечатать 25 лучших значений для «сайта», ранжированных по общему количеству «voice_up».

Как я могу сделать это на PHP?

Заранее спасибо,

John

Ответы [ 5 ]

1 голос
/ 06 августа 2009

Вы можете сделать что-то вроде этого (предупреждение: впереди крайне плохой SQL)

select site, sum(votes_up) votes_up
from (
    select site, votes_up from table_1
    UNION
    select site, votes_up from table_2
    UNION
    ...
    UNION
    select site, votes_up from table_56
) group by site order by sum(votes_up) desc limit 25

Но, как спросил Дэв, ваши данные имеют , чтобы быть такими? Есть гораздо более эффективные способы хранения данных такого типа.

Edit: Вы только что упомянули в комментарии, что вы ожидаете, что в будущем будет более 56 таблиц - я бы посмотрел ограничения MySQL на количество таблиц, которые вы можете UNION, прежде чем продолжить работу с этим видом SQL.

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

«Я разрешаю пользователям добавлять таблицы в базу данных». - Я надеюсь, что все ваши пользователи доброжелательны, заслуживают доверия и способны. Вы беспокоитесь о том, что люди отбрасывают или усекают таблицы, создают неправильные новые таблицы, которые нарушают ваш код, или другие подобные вещи? Какую защиту вы имеете, когда пользователи могут войти прямо в вашу базу данных и изменить схему?

Вот учебник по нормализации реляционных баз данных. Может быть, это поможет.

На тот случай, если кто-то, кто придет за вами, захочет найти, как это могло бы выглядеть, вот одна таблица, которая может делать то, что вы хотите:

create database bookfeather;
create user bookfeather identified by 'bookfeather';
grant all on bookfeather.* to 'bookfeather'@'%';

use bookfeather;

create table if not exists book
(
    id int not null auto_increment,
    title varchar(255) not null default '',
    upvotes integer not null default 0,
    downvotes integer not null default 0,
    primary key(id),
    unique(title)
);

Вы бы проголосовали за повышение или понижение ОБНОВЛЕНИЕМ:

update book set upvotes = upvotes + 1 where id = ?

Добавление новой книги так же просто, как добавление еще одной строки:

insert into book(title) values('grails in action')

Я настоятельно призываю вас пересмотреть.

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

Вот фрагмент кода PHP, который должен это сделать. Я не проверял его, поэтому он может содержать некоторые опечатки и прочее, обязательно замените DB_NAME

$result = mysql_query("SHOW TABLES");
$tables = array();
while ($row = mysql_fetch_assoc($result)) {
    $tables[] = '`'.$row["Tables_in_DB_NAME"].'`';

}

$subQuery = "SELECT site, votes_up FROM ".implode(" UNION ALL SELECT site, votes_up FROM ",$tables);
// Create one query that gets the data you need
$sqlStr = "SELECT site, sum(votes_up) sumVotesUp
            FROM (
            ".$subQuery." ) subQuery
           GROUP BY site ORDER BY sum(votes_up) DESC LIMIT 25";
$result = mysql_query($sqlStr);
$arr = array(); 
while ($row = mysql_fetch_assoc($result)) { 
    $arr[] = $row["site"]." - ".$row["sumVotesUp"];
} 
print_r($arr)

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

Основная идея заключается в том, чтобы перебирать все ваши таблицы (используя оператор SQL SHOW TABLES или аналогичный) в PHP, затем для каждой таблицы перебирать строки (SELECT site,votes_up FROM $table). Затем для каждой строки сверяйте сайт с массивом, который вы создаете с сайтами в качестве ключей, и голосуйте в качестве значений. Если сайт уже находится в массиве, увеличьте его голоса соответствующим образом; в противном случае добавьте его.

Неопределенно похожий на PHP псевдокод:

// Build an empty array for use later
$votes_array = empty_array();

// Get all the tables and iterate over them
$tables = query("SHOW TABLES");
for($table in $tables) {
    $rows = query("SELECT site,votes_up FROM $table");

    // Iterate over the rows in each table
    for($row in $rows) {
          $site = $row['site'];
          $votes = $row['votes_up'];

         // If the site is already in the array, increment votes; otherwise, add it
         if(exists_in_array($site, $votes_array)) {
             $votes_array[$site] += $votes;
         } else {
             insert_into_array($site => $votes);
         }
    }
}

// Get the sites and votes as lists, and print out the top 25
$sorted_sites = array_keys($votes_array);
$sorted_votes = array_values($votes_array);
for($i = 0; $i < 25; $i++) {
    print "Site " . $sorted_sites[$i] . " has " . $sorted_votes[$i] . " votes";
}
0 голосов
/ 06 августа 2009

Часть UNION ответа Иана Клелланда может быть сгенерирована с помощью следующего предложения. Таблица INFORMATION_SCHEMA.COLUMNS содержит столбец TABLE_NAME для получения всех таблиц.

select * from information_schema.columns 
where table_schema not like 'informat%'
and column_name like 'VOTES_UP'

Соедините все внутренние SELECT с помощью UNION ALL вместо UNION. UNION делает неявный DISTINCT (на оракуле).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...