LINUX.ORG.RU

Выбор и джойн последних записей по двум полям (год+квартал) из бд

 , ,


1

1

Гуру СУБД, подскажите куда копать, запутался как джойнить последние n записей по двум полям :)

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

Есть табличка с фирмами

company (id, name)
1, google
2, amazon

и табличка с оборотами этих фирм и композитным первичным ключом (company_id + year + quarter)

company_turnover (company_id, year, quarter, turnover)
1, 2024, 3, 100
1, 2024, 2, 90
2, 2023, 4, 20
2, 2023, 3, 30

Мне надо составить два запроса:

  1. К таблице company заджойнить данные по обороту за самый последний квартал последнего года которые есть в бд. Т.е. для каждой фирмы найти самый последний год/квартал и показать оттуда оборот, типа:
1, google, 2024, 3, 100
2, amazon, 2023, 4, 20

Я пробовал max, greatest, over, group by - и все они дают не совсем то что мне нужно - то берут макс год/квартал из всей таблицы а не для фирмы, то берут макс год и макс квартал а не их комбинацию и так далее.

  1. К таблице company заджойнить сумму оборотов за последние 4 квартала, типа:
1, google, 190
2, amazon, 50

Сюда я пока не совался пока с первым не разобрался, будет на десерт :)

ChatGPT дает много всего, но я в нем честно говоря не уверен. Он как-то как-будто переусложняет и не дает точно то что нужно мне.

★★★

а вы кстати в курсе, что сейчас 1-й квартал 25 года ? а 4-й 2024 уже закончился

и база то хоть какая ?

1) сферический селект: SELECT company_id,year,quarter,turnover FROM company_turnover GROUP BY company_id,year ORDER BY quarter LIMIT 1

2) по аналогии, но c SUM и будет счастье на зачёте :-)

PS мог ошибиться спросонок, но вроде бы так

PPS сопоставление с именем компашки добавьте сами - писать долго

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

а вы кстати в курсе, что сейчас 1-й квартал 25 года ? а 4-й 2024 уже закончился

Поэтому и условие что их надо брать из базы, не смотртя что сейчас на дворе. Ретроспектива так сказать :)

и база то хоть какая ?

Думал в тегах хватит упоминания что это постгрес :)

  1. сферический селект: SELECT company_id,year,quarter,turnover FROM company_turnover GROUP BY company_id,year ORDER BY quarter LIMIT 1

Логически тоже так пробовал, простой запрос нормально все выводит, а вот с джойном уже вопросы. Еще осложняется тем что потом это надо будет имплементировать в sqlalchemy :(

  1. по аналогии, но c SUM и будет счастье на зачёте :-)

Будем попробовать) Эх, сейчас бы назад в то время, когда надо было зачеты закрывать, а не решать реальные проблемы :))))

skyman ★★★
() автор топика
Последнее исправление: skyman (всего исправлений: 1)

Вобщем похоже получилось эту фигню победить. По крайней мере первый вопрос:

# Subquery to find company's turnovers sorted by year+quarter and row_number added
# latest year+quarter (e.g. 2024+3) row_number = 1
# previous year+qaurter (e.g. 2024+2) row_number = 2, etc
latest_turnover_subquery = session.query (
    CompanyTurnoverORM,
    func.row_number().over(
        partition_by=CompanyTurnoverORM.company_id,
        order_by=[desc(CompanyTurnoverORM.year), desc(CompanyTurnoverORM.quarter)]
    ).label('rn')
).subquery()

# Main query to join companies and latest turnover data
companies_query = (
	session.query(
	    CompanyORM,
	    latest_turnover_subquery.c.year,
	    latest_turnover_subquery.c.quarter,
	    latest_turnover_subquery.c.turnover
	).
	join(
	    latest_turnover_subquery,
	    CompanyORM.id == latest_turnover_subquery.c.company_id
	)
	.where(latest_turnover_subquery.c.rn == 1)  # We need row_number = 1, latest year+quarter seen in turnover table
	.all()
)
skyman ★★★
() автор топика

@phoenix @Psilocybe

Эксперты, нужна ваша экспертиза еще разок :-)

Подскажите как включить в джойн с RANK () OVER ( PARTITION BY фирмы для которых вообще нет данных в таблице company_turnover?

Т.е. для company (3, apple) строк с годом и кварталом в company_turnover нету, RANK() ничего не генерирует, условие WHERE rn=1 не включает apple в конечный результат.

Как бы показывать NULL или 0 для полей year, quarter, turnover?

1, google, 2024, 3, 100
2, amazon, 2023, 4, 20
3, apple, NULL, NULL, NULL
skyman ★★★
() автор топика
Ответ на: комментарий от phoenix

в примере от Psilocybe заменить join на right join/left join.

Первая мысль была такая же. Но не работает: для фирм без оборотов (apple) rn возвращается как NULL и отсекается where rn=1.

Если убираю where rn=1 то фирмы без оборотов показываются со всеми полями=NULL. Но для фирм у которых больше одной записи в оборотах показываются все, а не только последние.

select
  company.id,
  company.name,
  company_turnover.year,
  company_turnover.quarter,
  company_turnover.turnover,
  rn
from
  company
left JOIN (
  select
    company_turnover.company_id AS company_id,
    company_turnover.year AS year,
    company_turnover.quarter AS quarter,
    company_turnover.turnover AS turnover,
    row_number() OVER (PARTITION BY company_turnover.company_id ORDER BY company_turnover.year DESC, company_turnover.quarter DESC) AS rn
  from
    company_turnover) AS company_turnover
  on
    company.id = company_turnover.company_id
where
  rn = 1
skyman ★★★
() автор топика
Ответ на: комментарий от phoenix

or rn is null / or companytunrover.companyid is null

Спас! Благодарочка и рспект таким мозгам :) сам по глупости писал OR rn = NULL :)

where
  (rn = 1 or rn is null)
# sqlalchemy
.where(or_(latest_turnover_subquery.c.rn == 1, latest_turnover_subquery.c.rn == None))
skyman ★★★
() автор топика
Последнее исправление: skyman (всего исправлений: 1)
Ответ на: комментарий от MKuznetsov

а вы кстати в курсе, что сейчас 1-й квартал 25 года ? а 4-й 2024 уже закончился

А вы из какой эпохи пишете? 🤡

В СССР в определённых отраслях народного хозяйства хозяйственный год не совпадал с календарным и начинался с 1 октября. Соответственно, первым кварталом являлся период «октябрь — декабрь», вторым — «январь — март» и т. д.

aol ★★★★★
()
Ответ на: комментарий от aol

А вы из какой эпохи пишете? 🤡

из современной, в которой в гуглах,амазонах отчётность как в «В СССР в определённых отраслях народного хозяйства» и налоговый/отчётный год начинается с октября :-)

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

в которой в гуглах,амазонах

Тут лучше классика не скажешь )

Не знаю как там в Лондоне - я не была. Может, там собака - друг человека. А у нас - управдом друг человека!

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

aol ★★★★★
()
Ответ на: комментарий от aol

Тут бы не наводить тень на плетень, а уточнить у автора сначала.

если вы тему не читали, то не я тому виной :-) это как раз и было уточнение у автора и далее следовал его ответ

MKuznetsov ★★★★★
()
Ответ на: комментарий от skyman

select c.id as company_id,c.name,t.turnover
from company c left join
(
  select
     company_id, 
     turnover,
     row_number() over (partition by company_id order by year desc, quarter desc) rn
  from company_turnover
) t
 on c.id=t.company_id and t.rn=1

Psilocybe ★★★★
()
Последнее исправление: Psilocybe (всего исправлений: 3)