Модераторы: skyboy

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> MySQL, суммирование данных из неск. таблиц 
:(
    Опции темы
hollywood
Дата 4.5.2008, 05:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 20.10.2007

Репутация: нет
Всего: нет



Здравствуйте!

Уже пару дней воюю с проблемой, пробовал так и эдак, перелопатил кучу инфы, но что-то тяму не хватает. Поможите пожалуйста, люди добрые! smile

В принципе, суть задачи проста: есть несколько разных таблиц, в которых есть одинаковые поля. Допустим, это таблицы table_1 и table_2. В каждой из них есть поля user_id, quant, cost. user_id - это поле, описывающее, к кому относится запись, quant и cost - конкретные параметры данной записи.

Для примера:

--------------------
table_1: (user_id|quant|cost)
1    1  2
2    2  4
1    1  1

table_2: (user_id|quant|cost)
3    1  3
2    1   1
3    2   1

users: (id|name)
1  vasya
2  fedya
3  misha
--------------------

мне нужно сделать выборку из обоих таблиц (table_1, table_2) с группировкой по id пользователя (но вместо id нужно подставить имя). При этом величины из столбцов quant, cost нужно суммировать. Т.е. результатом выборки должна стать таблица:

vasya  2  3
fedya  3  5
misha  3  4

т.е. для каждого пользователя считается суммарное значение столбцов quant и суммарное значение столбцов cost из всех таблиц.

Помогите пожалуйста грамотно составить MySQL запрос, который это дело реализует. Пробовал сделать что-то вроде:

Код

SELECT `users`.`name`, (SUM(`table_1`.`quant`) + SUM(`table_2`.`quant`)) AS aggregate_quant,  (SUM(`table_1`.`cost`) + SUM(`table_2`.`cost`)) AS aggregate_cost
FROM `users`, `table_1`, `table_2`
WHERE (`table_1`.`user_id` = `users`.`id` || `table_2`.`user_id` = `users`.`id`)
GROUP BY (`users`.`name`)


в самых разнообразных вариациях. Ноль эффекта. У меня уже мозга за мозгу заходит.

Добавлено через 6 минут и 15 секунд
Мда, кстати, пробовал упростить запрос, чтобы разобраться в проблеме. По полочкам разложить так сказать. Для начала пытался делать без подстановки имени вместо id пользователя и суммирование делал только по одной таблице:
Код

SELECT `user_id`, SUM(`quant`), SUM(`cost`)
FROM `table_1`
GROUP BY (`user_id`)

тут все нормально.

но как только попробовал сделать выборку из 2х таблиц сразу:
Код

SELECT `user_id`, SUM(`table_1`.`quant`), SUM(`table_2`.`quant`)
FROM `table_1`, `table_2`
GROUP BY (`table_1`.`user_id`)

Сразу же результаты суммирования чуть не на порядок возрастают. Просто невообразимые числа откуда-то берутся. Почему так получается?
PM MAIL   Вверх
Deniz
Дата 4.5.2008, 06:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1251
Регистрация: 16.10.2004
Где: Новый Уренгой

Репутация: 6
Всего: 44



А вот так:
Код
select users.name, 
  (sum(table_1.quant + table_2.quant)) as aggregate_quant,
  (sum(table_1.cost + table_2.cost)) as aggregate_cost
from users
  left join table_1 on users.id = table_1.user_id
  left join table_2 on users.id = table_2.user_id
group by users.name

но если хоть одно quant или cost буде null, получишь null в соотв. столбце.

Это сообщение отредактировал(а) Deniz - 4.5.2008, 06:27


--------------------
"Для того чтобы сделать шаг вперед, достаточно пинка сзади" (с)
PM ICQ   Вверх
Akina
Дата 4.5.2008, 07:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



Я бы решал подзапросами или вьювами. Особенно с учетом того что user_id в таблицах данных имеет место повторяться:

1) суммирование quant и cost по первой таблице с группировкой по user_id 
2) то же, но по второй
3) left join полученных запросов в таблицу юзеров и суммирование с использованием проверок на null и замены таковых на нули (не помню функцию мускула)

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


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
hollywood
Дата 4.5.2008, 09:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 20.10.2007

Репутация: нет
Всего: нет



Большое спасибо за советы, прямо сейчас и попробую еще повоевать smile

Цитата(Akina @  4.5.2008,  07:38 Найти цитируемый пост)
Я бы решал подзапросами или вьювами.

2 небольших уточнения:
1) не совсем понял, что такое вьювы, а так же что за подзапросы? Насколько я знаю, мускул вложенных запросов ведь не поддерживает...
2) я работаю в связке php+mysql. разве можно одним вызовом mysql_query() сделать последовательно несколько связанных запросов?

если я правильно понял логику, можно сперва сделать два запроса, объединенных в union с выборками сумм столбцов для каждой таблицы, а потом выборку с суммированием еще по этой итоговой таблице? С 3-м шагом вроде понятно...
PM MAIL   Вверх
Akina
Дата 4.5.2008, 09:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



Цитата(hollywood @  4.5.2008,  10:32 Найти цитируемый пост)
Насколько я знаю, мускул вложенных запросов ведь не поддерживает...

Предлагаете поверить, что 
Цитата(hollywood @  4.5.2008,  06:43 Найти цитируемый пост)
перелопатил кучу инфы

?

А вообще начинать надо с озвучивания версий.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
hollywood
Дата 4.5.2008, 10:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 20.10.2007

Репутация: нет
Всего: нет



Цитата(Akina @  4.5.2008,  09:37 Найти цитируемый пост)
А вообще начинать надо с озвучивания версий.

Если быть честным, недавно перешел на связку php 5.2.4 + mysql 5.0.45. До этого работал с более старыми версиями. Вложенные запросы в мускуле появились с 4 версии, если верить тому, что я читал. Поэтому я не хотел их использовать, т.к. еще не совсем ясно, на каком хостинге будет работать скрипт.

Цитата(Akina @  4.5.2008,  09:37 Найти цитируемый пост)
Предлагаете поверить, что 
Цитата(hollywood @  4.5.2008,  06:43 )    
перелопатил кучу инфы    
?

"куча инфы" понятие относительное. Будем говорить так: речь идет об объеме информации, касающейся выборки из нескольких таблиц, найденной через поисковики за 3 дня. Форумы, мануалы и т.д. К сожалению, решить задачу самостоятельно, основываясь на полученной информации, мне не удалось. Честно говоря, в том, что касается языка SQL - я новичек.

Так что, если не в лом, дайте пожалуйста пример, как должны выглядеть запросы, согласно Вашей схеме.
PM MAIL   Вверх
Akina
Дата 4.5.2008, 10:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



Вот как это выглядит в Аксессе (без обработки)

Код

SELECT users.name, 
       IIf(IsNull([q1]![Sum-quant]),0,[q1]![Sum-quant])+IIf(IsNull([q2]![Sum-quant]),0,[q2]![Sum-quant]) AS AllQuant,
       IIf(IsNull([q1]![Sum-cost]),0,[q1]![Sum-cost])+IIf(IsNull([q2]![Sum-cost]),0,[q2]![Sum-cost]) AS AllCost
FROM 
(
  SELECT table2.user_id, 
         Sum(table2.quant) AS [Sum-quant], 
         Sum(table2.cost) AS [Sum-cost]
  FROM table2
  GROUP BY table2.user_id
) As q2 
RIGHT JOIN 
(
(
  SELECT table1.user_id, 
         Sum(table1.quant) AS [Sum-quant], 
         Sum(table1.cost) AS [Sum-cost]
  FROM table1
  GROUP BY table1.user_id
) As q1 
RIGHT JOIN 
users 
ON q1.user_id = users.id

ON q2.user_id = users.id;



--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
hollywood
Дата 4.5.2008, 10:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 20.10.2007

Репутация: нет
Всего: нет



Цитата(Deniz @  4.5.2008,  06:24 Найти цитируемый пост)
А вот так:
...
но если хоть одно quant или cost буде null, получишь null в соотв. столбце.


Попробовал сделать как Вы предложили. Конечные суммы вообще заоблачные получаются, совершенно неправдоподобные. Вот что высянилось из "ковыряний": я попробовал убрать группировку и вместо сумм в SELECT поставил "*", чтобы глянуть на конечную таблицу, из которой происходит выборка. Как говорится, "Атилла в недоумении": таблицы-то он сращивает, но при этом почему-то так получается, что в той таблице, в которой было больше записей, они удваиваются (т.е. каждой записи становистя вдвое больше), а в той, в которой меньше - просто чередуются.

У кого-нибудь есть ссылка на человечьий учебник или справочник, в котором есть описание команды JOIN? Меня уже достало это разтиражированное по всему инету руководство с php.ru, из которого про JOIN хрен что поймешь.
PM MAIL   Вверх
Akina
Дата 4.5.2008, 11:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



Цитата(hollywood @  4.5.2008,  11:51 Найти цитируемый пост)
У кого-нибудь есть ссылка на человечьий учебник или справочник, в котором есть описание команды JOIN? 

http://downloads.mysql.com/docs/refman-4.0-ru.html.zip 
пункт 6.4.1.1.



--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
hollywood
Дата 5.5.2008, 11:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 20.10.2007

Репутация: нет
Всего: нет



Цитата(Akina @  4.5.2008,  10:29 Найти цитируемый пост)
Вот как это выглядит в Аксессе (без обработки)

Спасибо огромное! Все работает!  smile  Но главное, что я понял, "как оно работает"  smile 

Кой-чего чего маленько переделал с учетом специфики структуры БД и данных, и вот, что получилось:
Код

SELECT name, SUM( quant ) , SUM( cost ) 
FROM (

SELECT user_id, quant, cost
FROM table_1
UNION ALL 
SELECT user_id, quant, cost
FROM table_2
) AS Total
RIGHT JOIN users ON Total.user_id = users.id
WHERE (
quant IS NOT NULL && cost IS NOT NULL 
)
GROUP BY (
user_id
)

Оп-ля!  smile  Просьба к гуру: гляньте, чего я тут наваял, ничего не напортачил?

Это сообщение отредактировал(а) hollywood - 5.5.2008, 11:19
PM MAIL   Вверх
Akina
Дата 5.5.2008, 11:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



Цитата(hollywood @  5.5.2008,  12:19 Найти цитируемый пост)
гляньте, чего я тут наваял, ничего не напортачил?

Трудно сказать "с учетом специфики структуры БД", но скобки вокруг поля в Group By могут превратить поле в выражение и привести к не-использованию индеса.
Это не арифметика, и избыток скобок может быть так же вреден, как и недостаток. 


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
hollywood
Дата 5.5.2008, 14:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 20.10.2007

Репутация: нет
Всего: нет



Цитата(Akina @  5.5.2008,  11:37 Найти цитируемый пост)
Трудно сказать "с учетом специфики структуры БД"

Да в-основном, это касается того, что поля quant и cost, либо оба NULL, либо оба не NULL (так, чтобы один был NULL, а другой нет - быть не может).

Цитата(Akina @  5.5.2008,  11:37 Найти цитируемый пост)
Это не арифметика, и избыток скобок может быть так же вреден, как и недостаток. 

Понял, учту.
PM MAIL   Вверх
Akina
Дата 5.5.2008, 14:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



Цитата(hollywood @  5.5.2008,  15:41 Найти цитируемый пост)
поля quant и cost, либо оба NULL, либо оба не NULL (так, чтобы один был NULL, а другой нет - быть не может).

А тогда зачем проверять оба?



--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
hollywood
Дата 6.5.2008, 11:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 20.10.2007

Репутация: нет
Всего: нет



Цитата(Akina @  5.5.2008,  14:47 Найти цитируемый пост)
А тогда зачем проверять оба?

А это чтоб парсеру жизнь медом не казалась... плюс, ну нельзя же, чтобы запрос уж слишком быстро производился. Несолидно как-то...  smile 

Чет я не подумал об этом моменте.
PM MAIL   Вверх
hollywood
Дата 6.5.2008, 22:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 20.10.2007

Репутация: нет
Всего: нет



Один неожиданный (по крайней мере, для меня) момент. Столбцы cost в моих таблицах - float(5,2). При попытке упорядочить "ORDER BY cost" (упорядочиваю самый "верхний" запрос в варианте с UNION'ами) наблюдается презабавнейшая катавасия. Упорядочивается это дело как угодно, но только не по цене. Это из-за "GROUP BY user_id" такое веселье получается?

Добавлено через 4 минуты и 48 секунд
 smile  Вот глупый чукча... 
Код

SELECT name, SUM( quant ) AS agr_quant , SUM( cost ) AS agr_cost
...
ORDER BY agr_cost

PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Составление SQL-запросов | Следующая тема »


 




[ Время генерации скрипта: 0.0816 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.