Прошу помочь с mySQL

Изображение пользователя MonoLife.

Приветствую!
Есть здесь гуру mySQL, готовые не много помочь? Буду рад помощи.

+1
MacLeod - 6 Август, 2015 - 16:19
Изображение пользователя MacLeod.

Don't ask to ask, just ask. В смысле задавайте, будет время - отвечу.

0
MonoLife - 6 Август, 2015 - 16:26
Изображение пользователя MonoLife.

спасибо, сейчас подготовлю вопрос!

0
kot040188 - 6 Август, 2015 - 16:38
Изображение пользователя kot040188.

В трёх экземплярах? ヅ

0
MonoLife - 6 Август, 2015 - 17:42
Изображение пользователя MonoLife.

Чтобы понять, чего хочу получить, начну с запроса №1, демонстрирующий выбор заявок, их сумм, количество поступлений и их суммы:

Результат:
Если использовать having, то получим заявки, по которым вся оплата прошла.

Теперь, запрос №2:

Результат:
Здесь группируем по наименованию компаний, подсчитываем количество заявок и поступлений, их суммы...
Если использовать having, то получим фирмы, по которым вся оплата прошла.
Какой день ломаю голову, как получить всё сгруппированное для фирм, но только количество заявок и поступлений должно равняться только выполненным, т.е. `debet`=0
По "Южной компании" должно получиться 2 заявки и 3 поступления.
Ниже дамп таблиц. Возможно, с проектированием что-то не так?
кажись со вторым запросом что-то намудрил:(
0
MonoLife - 7 Август, 2015 - 04:59
Изображение пользователя MonoLife.

Дамп:

В итоге, нужно получить
...
4 | 5 | Южная компания | 2 | 7583,52 | 3 | 7583.52 | 0
...

+2
MacLeod - 6 Август, 2015 - 22:10
Изображение пользователя MacLeod.

Ох... сразу два замечания:
1) никогда не используйте вложенные запросы, ибо, по мере накопления записей в таблицах, время выполнения запроса начнет возрастать до секунд, а то и десятков секунд;
2) при именовании таблиц, полей, да и переменных, при написании кода, не используйте не несущие смысла имена вроде b, idf, cr и т.д. - это делает код трудночитаемым не только для посторонних, но и для написавшего уже через пару недель, а также чревато ошибками.
По проектированию... я пока только бегло посмотрел.
Давайте так: опишите какие данные вам нужно получать, каким образом, что хранить, какие операции проводить и т.д., чтобы я целиком представлял задачу. А уже выборки по отчетности сделаем в конце.

0
MonoLife - 7 Август, 2015 - 04:56
Изображение пользователя MonoLife.

Благодарю за замечания и участие!

Теперь о задачах:
Как я понял, у мня получилась структура связи таблиц один-ко-многим.
Таблица jurnal — представлен ее сокращенный вариант. На самом деле, там будет еще много полей, «кто, что, когда, зачем и т.п.». Но в учебных целях, мне пока достаточно этих.
В данную таблицу заносятся заявки и их суммы (счет заявки) 'sumdoc' и т.п.
Поле 'id_firm' для связи с таблицей firms.'id'.
Таблица firms содержит наименование компаний по заявкам.
Следовательно, в первом случае, получаем связь один-ко-многим: наименование фирмы (firms.'n_short') → и ее заявки ( COUNT(jurnal.'id'), SUM(jurnal.'sumdoc') )
Таблица credit (возможно, правильней было бы ее назвать orders) содержит суммы поступления по каждой заявке и дату поступления. Т.е., по одной заявке может быть несколько поступлений. Credit, по всей видимости, у меня является связующей таблицей между firms и jurnal. В таблице credit кроме суммы поступления (поле 'postup') и даты поступления (поле 'datapost') имеются поля для связи с таблицами firms.'id' и jurnal.'id' — 'id_jur' и 'id_firm' соответственно.
В идеале, мне нужно получать сводную таблицу по запросам ко всем этим таблицам, с выводом на экран следующих данных:
1. «№ п/п»
2. «Наименование компании» ( поле 'n_short' т. firms )
3. «Количество заявок» ( count(jurnal.'id') )
4. «Сумма заявок» ( sum(jurnal.'sumdoc') )
5. «Количество поступлений» ( count(credit.'id') )
6. «Сумма поступлений» ( sum(credit .'postup') )
7. «Сумма остатка» ('debet': Сумма заявок-Сумма поступлений)

Примерно, то, что на второй картинке результата, приведенной ранее. Только без поля idf (id firms). Ну, а в будущем, делать более подробные выборки по каждой заявке или фирме.

Правда, в свете ваших замечаний, не представляю себе, как не использовать вложенные запросы при обращении к 3-м таблицам, если мне, к примеру, нужно будет получать фирмы, количество заявок и поступлений, суммы по дате поступления сумм (таблица credit 'datapost') и прочие данные по запросу из других таблиц одновременно, а одном запросе. Я впал в ступор:)

А самое главное, как выбрать фирмы, соответствующее количество заявок и их суммы, где сумма заявки = суммам поступлений, ('debet'=0)?
К примеру, для фирмы Южная компания (выделена желтым). Из первого запроса видно, что у этой фирмы 4 заявки, и 4 поступления ('cnt_cr'). Два поступления закрывают первую заявку ('id_jur' = 14) и одно поступление закрывают вторую заявку ('id_jur' = 17). По заявке 'id_jur' = 15 одно поступление и заявка не закрыта, по другому 'id_jur' = 16, поступлений вообще нет.
В итоге запроса для получения «закрытых» заявок должно было получиться:
«Наименование компании» - Южная компания
«Количество заявок» - 2
«Сумма заявок» - 7583,52
«Количество поступлений» - 3
«Сумма поступлений» - 7583.52
«Сумма остатка» - 0

Ох, надеюсь поняли, что я тут изложил. Сумбур, наверное какой-то..
PS: ошибка в данных, перезалил дамп

0
MonoLife - 7 Август, 2015 - 05:42
Изображение пользователя MonoLife.

Максимум без вложенного запроса я получил записи фирм и заявок для которых нет поступлений, и то, не уверен, что всё верно..

+1
MacLeod - 11 Август, 2015 - 05:12
Изображение пользователя MacLeod.

Например, так:
SELECT firms.n_short, SUM( credit.postup ) AS sum_post,
SUM( jurnal.sumdoc ) AS sum_zayav,
SUM( credit.postup ) - SUM( jurnal.sumdoc ) AS debet,
COUNT( DISTINCT credit.id ) AS count_post,
COUNT( DISTINCT jurnal.id ) AS count_zayav
FROM credit
LEFT JOIN firms ON firms.id = credit.id_firm
LEFT JOIN jurnal ON jurnal.id_firm = credit.id_firm
GROUP BY firms.id

Получаем:

Если нужно выбрать закрытые, добавляем
HAVING debet = 0
если наоборот, то
HAVING debet != 0
Настоятельно рекомендую почитать про различные типы джойнов, например, здесь.
При этом следует отметить, что UNION JOIN устарел; джойнить можно много таблиц различными способами, в том числе одну и ту же таблицу несколько раз под разными именами (только когда реально необходимо); понимать, что такое DISTINCT - выбор уникальных записей; в подавляющем большинстве случаев объединения работают на порядки быстрее вложенных запросов, однако, в очень редких случаях - наоборот, тут в помощь профайлер (хотя бы в phpMyAdmin и баловство с таблицами на 500к+ записей и полное осознание проделываемого).
Если я что-то упустил - спрашивайте.

0
MonoLife - 11 Август, 2015 - 07:48
Изображение пользователя MonoLife.

Спасибо, что возитесь со мной!:)
Думаете я не пробовал сразу с join без вложенных запросов? Пробовал и, к сожалению, не получается. Смотрите сами:
Приведенный пример вашего запроса:

дает не верный результат:

А вот мой запрос:
и верный результат:

Кроме того, в данном случае от HAVING нет проку, разве что посмотреть у каких фирм есть/нет задолженность.
Мне нужно получить количество заявок, количество поступлений и их суммы у которых debet=0. Повторюсь:
В итоге запроса для получения «закрытых» заявок должно было получиться:
«Наименование компании» - Южная компания
«Количество заявок» - 2
«Сумма заявок» - 7583,52
«Количество поступлений» - 3
«Сумма поступлений» - 7583.52
«Сумма остатка» - 0
0
MonoLife - 11 Август, 2015 - 10:42
Изображение пользователя MonoLife.

Вот как к этому прикрутить (приджойнить) поступления - кол-во и сумму?

Результат:
0
MacLeod - 11 Август, 2015 - 15:59
Изображение пользователя MacLeod.

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

0
Гость - 11 Август, 2015 - 16:57

Дело не в суммах. Выборки не идут в вашем примере.

0
MonoLife - 11 Август, 2015 - 17:14
Изображение пользователя MonoLife.

Вот я и думаю, может с проектированием таблиц что-то не так, раз не возможно обойтись без вложенных запросов.

0
MonoLife - 12 Август, 2015 - 08:21
Изображение пользователя MonoLife.

Вот как к этому прикрутить (приджойнить) поступления - кол-во и сумму?
Вот, получился монстр:

И, вроде, правильный результат:
Представляю, как будет тормозить такой запрос на больших объемах инфы:(
0
MonoLife - 16 Август, 2015 - 17:24
Изображение пользователя MonoLife.

видимо, на этом всё.

+1
MacLeod - 16 Август, 2015 - 19:49
Изображение пользователя MacLeod.

В принципе, подход верный, поскольку нужны две независимые группировки.
Первое, что я бы порекомендовал - нагенерить в таблицы, рост которых подразумевается наиболее сильно, по 200-300к записей. Именно случайных из определенных диапазонов, после чего заняться оптимизацией.
В данном месте
FROM
  `jurnal` , `firms`

запятая - то же самое, что INNER JOIN, и, если записать именно в этом виде - будет нагляднее и сразу заметно, что таблицу firms лучше джойнить уже в самом конце к полученному результату, а до этого работать только с айдишниками фирм. В противном случае - лишняя нагрузка по объединению, лишней сортировке и выбрасыванию дубликатов.
Здесь аналогично:
FROM `firms` , `credit`
То есть, в итоге, должно получиться три отдельных запроса (два сложных с группировкой и отдельный по firms) и джоины между ними. При этом, в WHERE тоже удастся избавиться от лишней сортировки и удаления дубликатов.
Далее нужно понять, насколько часто будут делаться подобные запросы по отношению к операциям вставки. Если раз в день/неделю/месяц - это одно, если несколько раз в минуту/секунду - нужно делать кэш, где будут храниться уже сгруппированные данные, которые будут пересчитываться по событию добавления записи.
Если фирм вообще будет немного (до 1к) их можно вообще всегда держать в памяти приложения, например, в мапе, тоже с обновлением по событию и "джойнить" уже в приложении.

0
MonoLife - 17 Август, 2015 - 03:20
Изображение пользователя MonoLife.

Благодарю за ценные замечания и советы!

Отправить комментарий

CAPTCHA на основе изображений
Введите цифры