SQL запрос с частичной группой с условием? - PullRequest
0 голосов
/ 24 февраля 2020

Ниже приведена проблема запроса SQL, для которой я не могу понять правильный подход:

Таблицы БД:

Employee: emp_id, emp_name
Credit: credit_id, emp_id, credit_date, credit_amount
debit: debit_id, emp_id, debit_date, debit_amount

Здесь каждый человек может иметь несколько доходов и расходов .

Требование к запросу: в конце каждого дня у каждого сотрудника будет свой актив («кредит до сих пор» - «дебет до сих пор»). Нам нужно найти пять лучших сотрудников с точки зрения максимального актива и даты, когда у них был этот максимальный актив.

Я пробовал следующий запрос, но, похоже, что-то упустил:

select Credit.emp_id, Credit.date, (Credit.income_amount - Debit.credit_amount) from 
(select emp_id, sum(amount) as credit_amount 
from credit) Credit
LEFT JOIN LATERAL (
     select emp_id, sum(amount) as debit_amount
     from debits
     where debits.emp_id = Credit.emp_id and Credit.date >= debits.date
     group by debits.emp_id
    ) Debit
ON true

Ответы [ 2 ]

2 голосов
/ 24 февраля 2020

Здесь я разбиваю запрос, чтобы сделать его более читабельным.

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

with 
credit as(
    select emp_id,credit_date date,sum(credit_amount) as amount
    from credit  
    group by 1,2),

debit as(
    select emp_id,debit_date,sum(debit_amount) as amount
    from expenses 
    group by 1,2),

Теперь нам нужно полное внешнее объединение подзапросов "кредит" и "дебет"

payments as (
    select distinct
    case when c.emp_id is null then d.person_id else c.emp_id  end as emp_id ,
    case when c.emp_id is null then d.date else c.date end as date,
    case when c.emp_id is null then 0 else i.amount end as credit ,
    case when d.emp_id is null then 0 else d.amount end as debit 
    from credit c
    full outer join debit d on d.emp_id=c.emp_id and d.date=c.date
    ),

Теперь мы возьмите накопленную сумму за день для кредита, дебета и общего баланса, как показано ниже.

total_balance as(
    SELECT emp_id, date, 
    sum(credit) OVER (PARTITION BY emp_id ORDER BY date asc) AS total_credit,
    sum(debit) OVER (PARTITION BY emp_id ORDER BY date asc) AS total_debit,
    (sum(income) OVER (PARTITION BY person_id ORDER BY date asc) - 
    sum(expense) OVER (PARTITION BY person_id ORDER BY date asc)) as total_balance
    FROM group_payment
    ORDER BY person_id, date),

Теперь нам нужно использовать функцию rank () для присвоения рейтинга на основе общего баланса (des c) для emp_id (ie. rank = 1 будет назначен наибольшему общему остатку за день для определенного emp_id). Запрос показан ниже.

ranks as (select emp_id,date,total_balance,
rank() over (partition by emp_id order by total_balance desc) as rank
from total_balance ),

Теперь выберите строки, имеющие ранг = 1 (ie. MAX of total_balance на день для emp_id и дату, на которую он был MAX). Закажите это по убыванию total_balance и выберите 5 верхних строк

emp_order as (select emp_id,date,total_balance 
from ranks
where rank=1
order by 3 desc
limit 5)

Теперь выберите имя из таблицы сотрудников.

select emp_id,name, date, total_balance as balance
from emp_order eo
join Employee e on e.emp_id = eo.emp_id
order by 4 desc
0 голосов
/ 24 февраля 2020

Группировка по сумме позволяет вам получить общий кредит для каждого человека в 1 записи. Вы можете сделать аналогичную вещь в подзапросе, чтобы вычесть дебет.

Select top 5 emp_id, credit_date, (sum(credit_amount) - 
(select sum(debit_amount) from debit d 
where c.emp_id = d.emp_id and c.credit_date = d.debit_date)
) as total
from Credit c group by emp_id, credit_date order by total
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...