Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Web программирование > SQL, базы данных
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 28.10.2014, 11:11   #1
Majestio
Пользователь
 
Аватар для Majestio
 
Регистрация: 12.07.2012
Сообщений: 65
По умолчанию Подсчет одним запросом. Возможно ли?

Доброго времени суток!

В процессе разработки отчета возникла задача относительно "хитрого" подсчета. Время поджимало - решил тремя запросами и частичным расчетом на клиенте. Но чувствую, то ли практики не хватает с SQL, то ли воображения. Посему, прошу ликбеза. Движок БД - PostgreSQL 9.3.2

Усеченная структура БД


Clients - хранит карточки клиентов
Service - хранит карточки обслуживаний
Service2Clients - хранит связки клиентов и обслуживаний (многие-к-многим)
RubricaNames - хранит каталог рубрикаторов
Rubricator - хранит рубрики по всем рубрикаторам
Points2Rubrica - хранит привязки значений по рубрикам к различным сущностям БД (например, к обслуживаниям)

Задача

Найти количество обслуживаний клиентов за период по группе рубрикаторов.

Моя неправильная реализация

Код:
SELECT r."Name", COUNT(s."Id") AS "Cnt" FROM (
  SELECT rn."Id", rn."Name" FROM public."RubricaNames" AS rn
  WHERE rn."Id" IN (90,91,92,93,94,134)
  ORDER BY rn."Name"
) AS r
LEFT OUTER JOIN  public."Rubricator" AS ru ON ru."GroupId" = r."Id"
LEFT OUTER JOIN  public."Points2Rubrica" AS pr ON pr."Rubrica" = ru."Id"
LEFT OUTER JOIN (
    SELECT * FROM public."Service" AS sv 
    WHERE sv."Date" >= '2011-09-01' AND sv."Date" <= '2014-09-01'
) AS s ON s."Id" = pr."Point"
GROUP BY r."Id",r."Name"
ORDER BY r."Name"
Результат



Неправильно следующее

  1. Цифры тут получаются недостоверные, т.к. считается не все. Подсчет идет по обслуживаниям, а не по обслуженным клиентам. Так как есть вероятность обслуживания группы - одно обслуживание на группу клиентов
  2. Не хватает одной строчки, в которой указано количество обслуживаний за указанный период без привязанных рубрикаторов по данной совокупности перечисленных рубрикаторов

Вообщем ... вот, ай нид хелп!
Мои программные ништякиhttps://majestio.info
Majestio вне форума Ответить с цитированием
Старый 28.10.2014, 11:56   #2
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 18,922
По умолчанию

А примерно так
Код:
SELECT rn.Name,COUNT(sc.Client)
  FROM RubricaNames rn
    LEFT JOIN Rubricator ru ON ru.GroupId = rn.Id
    LEFT JOIN Points2Rubrica pr ON pr.Rubrica = ru.Id
    LEFT JOIN Service sv ON ON sv.Id = pr.Point AND sv.Date BETWEEN '2011-09-01' AND '2014-09-01'
    LEFT JOIN Service2Clients sc ON sc.Service = sv.Id
  WHERE rn.Id IN (90,91,92,93,94,134)
  FROUP BY rn.Id,rn.Name
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар вне форума Ответить с цитированием
Старый 28.10.2014, 12:12   #3
Majestio
Пользователь
 
Аватар для Majestio
 
Регистрация: 12.07.2012
Сообщений: 65
По умолчанию

Попробовал - результаты совсем левые, все числа в 5-8 раз выше. Закономерности не заметил.
Мои программные ништякиhttps://majestio.info
Majestio вне форума Ответить с цитированием
Старый 28.10.2014, 12:24   #4
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 18,922
По умолчанию

а так
Код:
SELECT rn.Name,SUM(CASE WHEN sc.Client IS NULL 0 ELSE 1 END)
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар вне форума Ответить с цитированием
Старый 28.10.2014, 12:34   #5
Majestio
Пользователь
 
Аватар для Majestio
 
Регистрация: 12.07.2012
Сообщений: 65
По умолчанию

Цитата:
Сообщение от Аватар Посмотреть сообщение
а так
Нет, получается в первом ответе все верно - ни одно значение не превышает общее количество обслуженных клиентов. Сорри за поспешный вывод!)

Еще только одного не хватает в запросе - количества обслуживаний за указанный период, к которым не было ни одной привязки по указанным рубрикаторам.
Мои программные ништякиhttps://majestio.info
Majestio вне форума Ответить с цитированием
Старый 28.10.2014, 12:53   #6
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 18,922
По умолчанию

т.е. записей Service не имеющих ссылок с Service2Clients? Наверно только подзапросом
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар вне форума Ответить с цитированием
Старый 28.10.2014, 13:05   #7
Majestio
Пользователь
 
Аватар для Majestio
 
Регистрация: 12.07.2012
Сообщений: 65
По умолчанию

Цитата:
Сообщение от Аватар Посмотреть сообщение
т.е. записей Service не имеющих ссылок с Service2Clients? Наверно только подзапросом
Нет. Имеющих. Но ...

Не имеющих привязки ни по одной из рубрик (90,91,92,93,94,134). Иными словами - клиентов, получивших обслуживание, которое по указанным рубрикам вообще не рубрицировались.
Мои программные ништякиhttps://majestio.info
Majestio вне форума Ответить с цитированием
Старый 28.10.2014, 15:47   #8
evg_m
Старожил
 
Регистрация: 20.04.2008
Сообщений: 5,526
По умолчанию

Цитата:
Нет, получается в первом ответе все верно - ни одно значение не превышает общее количество обслуженных клиентов. Сорри за поспешный вывод!)

Еще только одного не хватает в запросе - количества обслуживаний за указанный период, к которым не было ни одной привязки по указанным рубрикаторам.
В основе лежит код
Цитата:
Сообщение от Аватар Посмотреть сообщение
А примерно так
Код:
SELECT rn.Name,COUNT(sc.Client)
  FROM RubricaNames rn
    LEFT JOIN Rubricator ru ON ru.GroupId = rn.Id
    LEFT JOIN Points2Rubrica pr ON pr.Rubrica = ru.Id
    LEFT JOIN Service sv ON ON sv.Id = pr.Point AND sv.Date BETWEEN '2011-09-01' AND '2014-09-01'
    LEFT JOIN Service2Clients sc ON sc.Service = sv.Id
  WHERE rn.Id IN (90,91,92,93,94,134)
  FROUP BY rn.Id,rn.Name
Код:
SELECT tp.tp,  tp.tpname, sum(cnt)
from  ( SELECT rn.tp, rn.tpname, count(sc.Client) as cnt
           FROM ( select id, case when id in (90,...134) then id else NULL end as tp, case when id in (90,...,134) then name else 'прочее' end as tpname
                       from RubricaNames ) as rn ---"исправляем" рубрикатор чтобы все остальные  рубрики имели общее наименование "прочее"
           LEFT JOIN Rubricator ru ON ru.GroupId = rn.Id
           LEFT JOIN Points2Rubrica pr ON pr.Rubrica = ru.Id
           LEFT JOIN Service sv ON ON sv.Id = pr.Point AND sv.Date BETWEEN '2011-09-01' AND '2014-09-01'
           LEFT JOIN Service2Clients sc ON sc.Service = sv.Id
           GROUP BY rn.id, rn.tpname  --считаем пока по всем кодам рубрикатора все "прочие" по отдельности
      ) as tp
GROUP BY tp.tp, tp.tpname     --"сворачиваем" (вычисляем сумму) по "прочим"
P.S. а может можно обойтись и одной группировкой
Код:
SELECT rn.tp, tp.tpname, count(sc.Client)
.....
GROUP BY rn.tp, rn.tpname
программа — запись алгоритма на языке понятном транслятору

Последний раз редактировалось evg_m; 28.10.2014 в 15:55.
evg_m вне форума Ответить с цитированием
Старый 28.10.2014, 15:54   #9
Vapaamies
Ваш К. О.
Участник клуба
 
Аватар для Vapaamies
 
Регистрация: 26.12.2012
Сообщений: 1,770
По умолчанию

Цитата:
Сообщение от Majestio Посмотреть сообщение
Еще только одного не хватает в запросе - количества обслуживаний за указанный период, к которым не было ни одной привязки по указанным рубрикаторам.
Это похоже на full join, но его, боюсь, в Access нет.
Vapaamies вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
выборка одним запросом limon142 PHP 1 25.05.2014 20:18
Выборка и подсчет кол-ва записей одним запросом WennY SQL, базы данных 1 02.07.2013 16:00
Выбрать данные из 2 таблиц одним запросом Linel SQL, базы данных 4 16.02.2011 15:29
Обновление двух строк одним запросом L_M SQL, базы данных 5 03.02.2011 02:01
BETWEEN и LIKE одним запросом Pinya SQL, базы данных 9 19.08.2008 11:30