SQL с несколькими count с разных таблиц

Запросы, планы, оптимизация запросов, ...

Модераторы: kdv, CyberMax

Ответить
SAN_i
Сообщения: 14
Зарегистрирован: 31 июл 2006, 19:24

SQL с несколькими count с разных таблиц

Сообщение SAN_i » 27 апр 2010, 11:24

Доброго времени суток.
Собственно дело обстоит так.
Использую Firebird 2.1.
Есть таблицы:
Сотрудники:

Код: Выделить всё

worker (
    id_worker    integer not null,
    f_name       varchar(200),
    s_name       varchar(200),
    th_name      varchar(200),
    h_phone      varchar(200),
    m_phone      varchar(200),
    address      varchar(200),
    b_day        varchar(2),
    b_month      varchar(10),
    b_year       varchar(4),
    id_state     integer,
    id_position  integer,
    bar_code     integer,
    isdel        varchar(10),
    whydel       varchar(200)
);
Клиенты:

Код: Выделить всё

client (
    id_client       integer not null,
    bar_code        integer,
    id_worker       integer,
    id_state        integer,
    f_name          varchar(200),
    s_name          varchar(200),
    th_name         varchar(200),
    b_day           varchar(2),
    b_month         varchar(10),
    b_year          varchar(4),
    photo           blob sub_type -1 segment size 16384,
    address         varchar(200),
    hphone          varchar(200),
    mphone          varchar(200),
    email           varchar(200),
    clwork          varchar(200),
    other           varchar(200),
    id_info         integer,
    id_advertising  integer,
    isdel           varchar(10),
    whydel          varchar(200)
);
И таблица-связь, связывающая клиентов с купленными ими абонементами:

Код: Выделить всё

cl_have_contract (
    id_cl_have_contract  integer not null,
    id_client            integer,
    id_contract          integer,
    id_worker            integer,
    start_day            varchar(2),
    start_month          varchar(10),
    start_year           varchar(4),
    stop_day             varchar(2),
    stop_month           varchar(10),
    stop_year            varchar(4),
    freez_day            varchar(2),
    freez_month          varchar(10),
    freez_year           varchar(4),
    ifend                varchar(10),
    isdel                varchar(10),
    whydel               varchar(200)
);
В таблицах есть поле "id_worker" по которому ведётся учёт какой сотрудник добавил ту или иную запись в БД.
Пытаюсь сделать запрос чтоб получить примерно такую таблицу(отчёт по сотрудникам):
________________________________________________________________________________________________
|Сотрудник(ФИО) | Количество проданных абонементов| Количество зарегистрированных клиентов |
|________________|____________________________________|_________________________________________|
Вот мой SQL:

Код: Выделить всё

select w.id_worker, w.s_name, w.f_name, w.th_name, count(hc.id_worker) as w_ct, count(c.id_worker) as w_c
from worker w, cl_have_contract hc, client c
where (w.id_worker = hc.id_worker)  and (w.id_worker = c.id_worker)
group by w.id_worker, w.s_name, w.f_name, w.th_name
order by w.id_worker
Есть две проблемы с которыми не могу разобраться:
1 Если какой то из сотрудников не добавлял, к примеру, контрактов, а клиентов вносил в БД то этот сотрудник в результате запроса не будет отображён
2 Почему то неправильно считается количество записей, к примеру, в таблице-связи контрактов всего 7 записей, а count сотрудника выдаёт 96

Помогите разобраться, пожалуйста с данными вопросами. Большое спасибо.
Последний раз редактировалось SAN_i 27 апр 2010, 14:43, всего редактировалось 1 раз.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Re: SQL с несколькими count с разных таблиц

Сообщение kdv » 27 апр 2010, 14:30

"абонЕмент", "зарегИстрированный".

Правильная связь таблиц для денормализации будет:

Код: Выделить всё

from worker w, cl_have_contract hc, client c
where (w.id_worker = hc.id_worker)  and (hc.id_client = c.id_client)
в оригинальном запросе связь с таблицей c "не та". Или надо использовать count(distinct ...

www.ibase.ru/devinfo/joins.htm

Если считать кол-во клиентских контрактов по конкретному работнику, то таблица clients тут вообще не нужна.
В примитивном виде это
select id_worker, count(id_client)
from cl_have_contract
group by id_worker

А по кол-ву клиентов, зарегистрированных работников - такой же запрос только по clients. То есть, получается 2 разных агрегата. Попробуйте derived tables.
В любом случае, уберите сначала группировку и count, и посмотрите на данные запроса. Там будет понятно, сколько записей и как они посчитаются.

SAN_i
Сообщения: 14
Зарегистрирован: 31 июл 2006, 19:24

Re: SQL с несколькими count с разных таблиц

Сообщение SAN_i » 27 апр 2010, 15:15

Код: Выделить всё

where (w.id_worker = hc.id_worker)  and (hc.id_client = c.id_client)
Таблица "cl_have_contract" является связью для таблиц client и contract, поле id_worker в cl_have_contract нужно только для ведения статистики, истории того какой пользователь продал тот или иной абонемент.
Посмотрел и сформировал запрос по вашему совету, такой:

Код: Выделить всё

select w.id_worker, w.s_name, w.f_name, w.th_name
from worker w join cl_have_contract hc on w.id_worker = hc.id_worker
              join client c on c.id_worker = w.id_worker
Вывело большой список, такого количества записей у меня естественно нет, буду думать как организовать мой запрос.

Вопрос таков возможно ли сделать выборку содержащую несколько count по разным таблицам? Если да то направьте, пожалуйста. Или же эти данные лучше как то собирать из нескольких запросов?

SAN_i
Сообщения: 14
Зарегистрирован: 31 июл 2006, 19:24

Re: SQL с несколькими count с разных таблиц

Сообщение SAN_i » 28 апр 2010, 12:16

Запрос подправил.
Получился такой:

Код: Выделить всё

select w.id_worker, w.f_name, w.s_name, w.th_name, s.w_c, count(hc.id_worker) as w_ct
from (
        select c.id_worker, count(c.id_worker) as w_c
        from client c
        group by c.id_worker
    ) s, worker w, cl_have_contract hc
where (w.id_worker = s.id_worker) and (w.id_worker = hc.id_worker)
group by w.id_worker, w.f_name, w.s_name, w.th_name, s.w_c
Как уже говорилось ранее, я хочу сделать отчёт по сотрудникам, проблема остаётся в том что у меня есть два сотрудника один из которых добавлял и клиентов и абонементы, а второй только клиентов. Проблема в том что второй сотрудник в результате этого запроса не отображается. Подскажите как сделать так чтоб при отсутствующей записи count выдавал 0 и отображал запись, вместо того чтоб скрыть её?

Ответить