2014-11-14 2 views
1

Мне нужно определить лучший способ сделать несколько агрегатов для разных таблиц, которые объединены в запрос SQL.Объединение результатов из разных таблиц в одном запросе SQL

Учитывая следующие таблицы для управления гостиницей, планирования обслуживания, советами клиентов и оценками клиентов:

Room 
id | name 
----+------ 
    1 | 101 
    2 | 102 
    3 | 103 
    4 | 201 
    5 | 202 
    6 | 203 

housekeeper 
id | name | age 
----+----------+----- 
    1 | John  | 48 
    2 | Veronica | 25 
    3 | Bob  | 19 

room_service_planning 
id | date | room_id | housekeeper_id 
----+------------+---------+---------------- 
    1 | 2014-11-01 |  3 |    2 
    2 | 2014-11-01 |  1 |    2 
    3 | 2014-11-02 |  5 |    1 

tips 
id | amount | housekeeper_id 
----+--------+---------------- 
    1 | 5,00 € |    1 
    2 | 2,00 € |    3 
    3 | 2,00 € |    1 
    4 | 3,00 € |    3 


client_eval 
id | good_eval | housekeeper_id 
----+-----------+---------------- 
    1 | t   |    1 
    2 | f   |    1 
    3 | t   |    2 
    4 | t   |    2 

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

Ожидаемый результат при поиске обслуживания между 2014-11-01 и 2014-11-02 это что-то вроде:

id | date | room_id | housekeeper_id | hk_name | hk_tips_sum | hk_tot_eval | hk_pos_eval 
----+------------+---------+----------------+----------+-------------+-------------+------------- 
    1 | 2014-11-01 |  3 |    2 Veronica       2    2 
    2 | 2014-11-01 |  1 |    2 Veronica       2    2 
    3 | 2014-11-02 |  5 |    1  John  7,00 €    2    1 

Растворов я исследовал, чтобы получить этот результат:

решения 1:

SELECT temp2.id as id, temp2.date as date, temp2.room_id as room_id, 
temp2.housekeeper_id as housekeeper_id, temp2.hk_name as hk_name, 
temp2.hk_tips_sum as hk_tips_sum, temp2.hk_tot_eval as hk_tot_eval, 
count(1) as hk_post_eval 
FROM 

    (
    SELECT temp.id as id, temp.date as date, temp.room_id as room_id, 
    temp.housekeeper_id as housekeeper_id, temp.hk_name as hk_name, 
    temp.hk_tips_sum as hk_tips_sum, count(1) as hk_tot_eval 

    FROM 

     (SELECT rsp.id as id, rsp.date as date, rsp.room_id as room_id, 
     rsp.housekeeper_id as housekeeper_id, hk.name as hk_name, 
     sum(t.amount) as hk_tips_sum 
     FROM room_service_planning rsp 
     INNER JOIN housekeeper hk 
      ON rsp.date>='2014-11-01' 
      AND rsp.date<='2014-11-02' 
      AND hk.id=rsp.housekeeper_id 
     LEFT JOIN tips t 
      ON t.housekeeper_id=hk.id 
     GROUP BY rsp.id, rsp.date, rsp.room_id, rsp.housekeeper_id, hk_name 
     ) temp 

    LEFT JOIN client_eval ce_tot 
     ON ce_tot.housekeeper_id=temp.housekeeper_id 

    GROUP BY temp.id, temp.date, temp.room_id, temp.housekeeper_id, 
     temp.hk_name, temp.hk_tips_sum 

    ) temp2 

LEFT JOIN client_eval ce_pos 
    ON ce_pos.housekeeper_id=temp2.housekeeper_id 
    AND ce_pos.good_eval='t' 

GROUP BY temp2.id, temp2.date, temp2.room_id, temp2.housekeeper_id, 
temp2.hk_name, temp2.hk_tips_sum, temp2.hk_tot_eval; 

Примечание: это основано на «группе агрегировать» т «присоединитесь к следующей таблице», затем «группируйте по агрегированию», затем «присоединитесь к следующей таблице» и т. д. .... Это работает, но очень тяжело писать и читать трудно. Я не удовлетворен этим решением.

Решение 2:

SELECT rsp.id as id, rsp.date as date, rsp.room_id as room_id, 
rsp.housekeeper_id as houkeeper_id, hk.name as hk_name, 
t.amount as hk_tips_sum, ce_tot.hk_tot_eval as hk_tot_eval, 
ce_pos.hk_pos_eval as hk_pos_eval 
FROM room_service_planning rsp 
INNER JOIN housekeeper hk 
    ON rsp.date>='2014-11-01' 
    AND rsp.date<='2014-11-02' 
    AND hk.id=rsp.housekeeper_id 
LEFT JOIN 
    (SELECT housekeeper_id, sum(amount) as amount 
    FROM tips 
    GROUP BY housekeeper_id) t 
    ON t.housekeeper_id=hk.id 
LEFT JOIN 
    (SELECT housekeeper_id, count(1) as hk_tot_eval 
    FROM client_eval 
    GROUP BY housekeeper_id) ce_tot 
    ON ce_tot.housekeeper_id=hk.id 
LEFT JOIN 
    (SELECT housekeeper_id, count(good_eval) as hk_pos_eval 
    FROM client_eval 
    WHERE good_eval='t' 
    GROUP BY housekeeper_id) ce_pos 
    ON ce_pos.housekeeper_id=hk.id; 

Примечание: это решение более читаемым, но мне интересно, что происходит, число записей растет на «советы» или «client_eval». Предположим, что в отеле миллионы подсказок и миллионы клиентов eval. Это означает, что мы будем делать миллионы сумм и счетов, а затем мы просто выберем те из них, которые вам нужны. Это пустая трата ресурсов и может привести к очень долгим задержкам.

Заключение: Несмотря на то, что я нашел два разных способа достижения своей цели, я не удовлетворен ими.

Какое умное и эффективное решение вы могли бы предложить решить эту проблему?

+0

Ваши оценки не подключен к услуге. Похоже, что в конце концов вы получаете неправильный оценочный номер. –

+1

Пила тоже, но проблема заключается в том, что агрегаты предназначены для карьеры экономки, а не для предстоящих (и как таковых, не связанных или связанных с оценками) запланированного назначения услуг. –

+0

Вы правы, эта система не полностью согласована. Я просто построил его, чтобы объяснить мою проблему. Моя оригинальная система слишком сложна, чтобы объясняться здесь. – Nitseg

ответ

1

Я вижу здесь пару вещей. Я на самом деле серьезно не использовал postgresql через некоторое время, поэтому я надеюсь, что я не полностью покину.

Если вы хотите просто получить общую информацию, связанную с домохозяйствами, чтобы присоединиться к ежедневному графику, вам может потребоваться создать представление, которое инкапсулирует идентификатор домохозяйства, общие советы, общие оценки и общие положительные оценки. Это должно использовать любое кэширование на уровне сервера и уменьшать количество необходимых вызовов функций.

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

SELECT 
    rsp.id as id, rsp.date as date, rsp.room_id as room_id, 
    rsp.housekeeper_id as housekeeper_id, hk.name as hk_name, 
     (SELECT SUM(t.amount) from tips where housekeeper_id = rsp.housekeeper_id) as hk_tips_sum, 
     (SELECT COUNT(1) from client_eval where housekeeper_id = rsp.housekeeper_id) as hk_eval_count, 
     (SELECT COUNT(1) from client_eval where housekeeper_id = rsp.housekeeper_id and good_eval='t') as hk_positive_eval_count 
    FROM room_service_planning rsp 
     INNER JOIN housekeeper hk 
      ON rsp.date>='2014-11-01' 
      AND rsp.date<='2014-11-02' 
      AND hk.id=rsp.housekeeper_id 

Это будет только вычислить агрегаты, где они необходимы, если мнение переполнен.

И, наконец, важно ли это, какие изменения приносят советы/оценки?Это может иметь смысл для внешнего ключа их к таблице room_service_planning вместо таблицы экономки, или в дополнение к таблице экономки, если вы не всегда знаете, какой из гостей дал отзыв/отзыв.

+0

Спасибо Брайан. Я буду копаться в взглядах. Я никогда не использовал их раньше. Ваше второе решение интересно, хотя оно не будет работать в моей исходной системе. Кажется, я упростил это, так как информация экономки полностью независима от room_service. В моей первоначальной системе мне нужно, чтобы советы были суммированы только в определенных условиях, заданных предыдущей операцией JOIN. – Nitseg

+0

Получите сумму советов только при определенных обстоятельствах (все советы, когда домработник = удивительный), или включают только подсказки, соответствующие определенным критериям в сумме (всегда получайте сумму советов, но только за советы> .05 €)? –

+0

Не сосредотачивайтесь на этом примере, так как он плохо построен. Здесь я должен был объяснить, что я намерен делать. Предположим, что советы в этом случае должны учитываться (суммой) только в независимых обстоятельствах. – Nitseg

0

попробовать это:

select * FROM (
     room_service_planning rsp 
     INNER JOIN housekeeper hk on hk.id=rsp.housekeeper_id 
    ) 
left join (SELECT housekeeper_id,SUM(amount) hk_tips_sum from 
       tips group by 1) tips using (housekeeper_id) 
left join (SELECT housekeeper_id,COUNT(*) hk_eval_count, 
        count(NULLIF(good_eval,false)) hk_positive_eval_count 
      from client_eval group by 1) evals using (housekeeper_id) 
where rsp.date>='2014-11-01' and rsp.date<='2014-11-02' 
+0

Привет, не имеет ничего общего с темой, но вы учились в IUT de Bayonne в 1995 году? – Nitseg

+0

Возможно: –

+0

ваши инициалы: M.G? –

Смежные вопросы