Слияние значений из второй таблицы по общим внешним ключам - PullRequest
0 голосов
/ 03 февраля 2020

Объяснение схемы

У меня есть две таблицы с одинаковой структурой внешних ключей. Они содержат значения из аналогичного домена - в общем, это информация о ценах пользователей. Существует две таблицы, потому что во второй таблице содержатся цены, которые были дополнительно сгенерированы для других пользователей, - существует связь 1: n между пользователями, указывающими, для кого можно создавать дополнительные цены.

Давайте назовем эти таблицы pricing и referral_pricing:

pricings:
id | date | user_id | tenant_id | zone_id | price
referral_pricings:
id | date | user_id | tenant_id | zone_id | price
users:
id | email | password | pricing_parent_id
1    test    test       null
2    test_2  test_2     1

Каждый раз, когда пользователь вставляет в таблицу pricing, автоматически выполняется вторая вставка в таблицу referral_pricings, например:

INSERT INTO pricings VALUES(null, NOW(), 1, 1, 1, 1000); // for user 1
INSERT INTO pricings VALUES(null, NOW(), 2, 1, 1, 1000); // for user 2
INSERT INTO referral_pricings VALUES(null, NOW(), 2, 1, 1, 200); // because pricing_parent_id != null for user with ID 2, I automatically insert 20% of total price as a referral price

Это означает, что когда я хочу получить общую цену для пользователя 1, то это то, что я хочу получить:

user_id | sum(price) | sum(referral_price)
1         1000       | 200

Поскольку я получаю общую цену для пользователя 1 из таблицы pricings и общая цена от referral_pricings пользователями, для которых users.pricing_parent_id == 1.


Проблема

Проблема в том, что я хочу, чтобы этот запрос был очень динамичным c - разрешить группировку по внешним ключам и различным форматам даты. И поскольку они не связаны каким-либо общим внешним ключом:

Если я определю отношение, например:

Pricing.php:

public function referral_pricings()
{
  return $this->belongsTo(ReferralPricing::class, 'date', 'date');
}

ReferralPricing.php:

public function pricings()
{
  return $this->belongsTo(Pricing::class, 'date', 'date');
}

Тогда, когда я группирую по моему запросу, например, по году:

$pricings = Pricing::groupBy('YEAR(date)')->with('referral_pricing')->get();

Неправильный загруженный запрос:

SELECT date, sum(price)
FROM referral_pricings
WHERE date = 'YEAR(2020)'
GROUP BY YEAR(2020);

То же самое, если я хочу сгруппировать по большему количеству значений, например:

$pricings = Pricing::groupBy(['YEAR(date)', 'tenant_id'])->with('referral_pricing')->get();

Тогда запрос отношения:

SELECT date, tenant_id, sum(price)
FROM referral_pricings
WHERE date = 'YEAR(2020)'
GROUP BY YEAR(2020), tenant_id;

Что также не имеет смысла, потому что здесь нет никакого отношения к tenant_id. Эти таблицы просто не могут быть связаны.


Решение

Я сделал это, используя объединение из обеих таблиц и применив group by к результату еще раз:

$pricings = Pricing::addSelect([
  'YEAR(date) as date',
  'tenant_id',
  'sum(price) as price',
  '0 as referral_price'
])
->groupBy(['date', 'tenant_id']);

$referral_pricings = ReferralPricing::addSelect([
  'YEAR(date) as date',
  'tenant_id',
  '0 as price',
  'sum(price) as referral_price'
])
->groupBy(['date', 'tenant_id'];

$union = DB::query()
  ->fromSub($pricings->union($referral_pricings), 't')
  ->addSelect([
    'YEAR(date) as date',
    'tenant_id',
    'sum(price) as price',
    'sum(referral_price) as referral_price'
  ])
  ->groupBy(['t.date', 't.tenant_id']);

Это прекрасно работает, но это означает ОЧЕНЬ МНОГО пользовательских логий c, гораздо меньшую гибкость и необходимость обрабатывать все объединения самостоятельно, без возможности использовать красноречивые отношения (потому что это DB::query() из таблицы объединения в конце).

Есть ли лучшее решение для этого?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...