SQL-запрос получает общую стоимость, основанную на разной цене за единицу, количестве в разное время

У меня есть таблица транзакций, которая выглядит так: количество - это общее количество на складе, основанное на разной цене за единицу. назовем это T

id | transaction_time | item | unit_price | quantity | subtotal
1      2012-5-15          A         1.00         15         15.00
2      2012-5-15          A         3.00         15         45.00
3      2012-5-15          B         1.00         10         10.00
4      2012-6-10          A         2.00         15         30.00
5      2012-6-15          A         2.00         10         20.00

Мне нужно получить общую стоимость каждого товара на складе с течением времени ... однако одни и те же товары основаны на разной цене за единицу. Например, результат для A:

transaction_time | item |  quantity | subtotal
    2012-5-15          A     30         60.00
    2012-6-10          A     45         90.00
    2012-6-15          A     40         80.00

2012-5-15, у нас есть 15 предметов A с ценой 1,00, 15 предметов A с ценой 3,00, поэтому общее количество составляет 30, промежуточный итог составляет 15 * 1 + 15 * 3 = 60.

2012-6-10 у нас есть еще 15 товара A с ценой 2, поэтому общее количество становится 30 + 15 = 45, промежуточный итог становится 60 + 15 * 2 = 90

2012-6-15 у нас есть 10 предметов A с ценой 2, поэтому предмет A с ценой 2 снижается с 15 до 10. общее количество становится 40, а промежуточный итог уменьшается -2 * 5, что становится 80.

Я пытался

select transaction_time,sum(quantity),sum(subtotal)
where id in(select max(id) from T group by unit_price,item)
group by item
having item=A

Это дает мне только последнюю строчку

2012-6-15          A     40         80.00

Что ты пробовал? Кроме того, я изо всех сил пытаюсь понять арифметику

Strawberry 09.06.2018 07:26

Набор результатов для A на 2012-6-10 и 2012-6-15 не совпадает с предоставленными входными данными, по крайней мере, не очевидным образом. Не могли бы вы объяснить, как получаются количественные значения 45 и 35?

Giorgos Betsos 09.06.2018 07:27

обновленное объяснение.

weeo 09.06.2018 07:34

@GiorgosBetsos обновленное объяснение ..

weeo 09.06.2018 07:36

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

P.Salmon 09.06.2018 08:07

Сложный вопрос, мне нравится и работаю над ним @weeo

Muhammad Vakili 09.06.2018 08:08

@Muhammadvakili, да, это так ... Я добавил цену за единицу в существующую таблицу и попытался увидеть изменение уровня запасов, которое у меня было раньше. Тогда у меня есть этот сложный вопрос.

weeo 09.06.2018 08:13

@ P.Salmon рассчитывается на основе цены товара и единицы. эти 2 работают как первичный ключ для отслеживания количества товара с этой ценой за единицу.

weeo 09.06.2018 08:14

Это не сложно. Это просто помешательство.

Strawberry 09.06.2018 08:14

@Strawberry help!

weeo 09.06.2018 08:15

Итак, если количество меньше, чем предыдущее, итоги должны снизиться?

P.Salmon 09.06.2018 08:17

Я не квалифицирован с медицинской точки зрения

Strawberry 09.06.2018 08:18

@ P.Salmon да! запись с тем же товаром и ценой за единицу отменяет предыдущую запись

weeo 09.06.2018 08:20

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

Giorgos Betsos 09.06.2018 09:10

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

weeo 09.06.2018 09:13

Да, я думаю, что сложность запроса намекает на изменение вашей схемы.

Giorgos Betsos 09.06.2018 09:20

@GiorgosBetsos Моя цель - сохранить историю количества и общей стоимости в одной таблице для предметов с разной ценой за единицу. Думаю, это будет проще, чем вести 2 стола ...

weeo 09.06.2018 09:47
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
17
1 065
2

Ответы 2

Следующий запрос (сложный, возможно, медленный, требует оптимизации) работает, проверьте ДЕМО

SELECT tr_sub.cur_tt, tr_sub.item, sum(tr.quantity), sum(tr.quantity*tr.unit_price) 
FROM 
  (SELECT tr1.transaction_time as cur_tt, max(tr2.transaction_time) as prev_tt, tr1.item as item, 
     IF (tr1.unit_price=tr2.unit_price, tr1.unit_price, tr2.unit_price) as t_p 
     FROM transactions tr1 LEFT JOIN transactions tr2 ON 
     tr1.transaction_time>=tr2.transaction_time AND tr1.item=tr2.item
    GROUP BY tr1.item, tr1.transaction_time,  t_p
   ) as tr_sub INNER JOIN transactions tr ON 
   tr_sub.prev_tt=tr.transaction_time 
   AND tr_sub.item=tr.item 
   AND tr_sub.t_p=tr.unit_price
GROUP BY tr_sub.item, tr_sub.cur_tt
ORDER BY tr_sub.cur_tt, tr_sub.item

Я не вижу ваших изменений в ссылке, вам нужно ее разветвить, изменить ее и создать новую кодовую стену.

Peeyush 09.06.2018 09:00

Да, вы правы, извините за это. Отметьте это. Посмотри запись 16.06.2012 A 15 2. Значение 15 неверно, потому что оно не самое актуальное для этого unit_price.

Giorgos Betsos 09.06.2018 09:07

Я обновил решение, оно должно решить проблему

Peeyush 09.06.2018 09:50

Сначала вам нужно определить все возможные значения unit_price для конкретного элемента:

SELECT DISTINCT unit_price
FROM t
WHERE item = 'A'

Выход:

unit_price
----------
1
3
2

Также необходимо идентифицировать все возможные transaction_times:

SELECT DISTINCT transaction_time
FROM t
WHERE item = 'A';

Выход:

transaction_time
----------------
2012-05-15
2012-06-10
2012-06-15

Теперь выполните CROSS JOIN между двумя вышеуказанными наборами.

SELECT *
FROM (
   SELECT DISTINCT transaction_time
   FROM t
   WHERE item = 'A') AS times
CROSS JOIN (
   SELECT DISTINCT unit_price
   FROM t
   WHERE item = 'A') AS up
ORDER BY times.transaction_time   

получить:

transaction_time unit_price
----------------------------
2012-05-15       3
2012-05-15       2
2012-05-15       1
2012-06-10       3
2012-06-10       2
2012-06-10       1
2012-06-15       1
2012-06-15       3
2012-06-15       2

Теперь используйте приведенное выше и выполните коррелированный подзапрос, чтобы получить unit_price на transaction_time из элемента 'A':

SELECT transaction_time, unit_price,
       (SELECT quantity
        FROM t
        WHERE t.item = 'A' 
              AND t.unit_price = up.unit_price
              AND t.transaction_time <= times.transaction_time
        ORDER BY transaction_time DESC LIMIT 1) AS quantity
FROM (
   SELECT DISTINCT transaction_time
   FROM t
   WHERE item = 'A') AS times
CROSS JOIN (
   SELECT DISTINCT unit_price
   FROM t
   WHERE item = 'A') AS up
ORDER BY times.transaction_time

Выход:

transaction_time     unit_price  quantity
----------------------------------------
15.05.2012 00:00:00  1           15
15.05.2012 00:00:00  3           15
15.05.2012 00:00:00  2           NULL
10.06.2012 00:00:00  1           15
10.06.2012 00:00:00  3           15
10.06.2012 00:00:00  2           15
15.06.2012 00:00:00  1           15
15.06.2012 00:00:00  3           15
15.06.2012 00:00:00  2           10

Конечный результат - это просто выполнение GROUP BY на указанном выше:

SELECT transaction_time, 
       'A' AS item,
       SUM(quantity) AS quantity,
       SUM(quantity*unit_price) AS subtotal
FROM (           
    SELECT transaction_time, unit_price,
           (SELECT quantity
            FROM t
            WHERE t.item = 'A' 
                  AND t.unit_price = up.unit_price
                  AND t.transaction_time <= times.transaction_time
            ORDER BY transaction_time DESC LIMIT 1) AS quantity
    FROM (
       SELECT DISTINCT transaction_time
       FROM t
       WHERE item = 'A') AS times
    CROSS JOIN (
       SELECT DISTINCT unit_price
       FROM t
       WHERE item = 'A') AS up) AS x
GROUP BY transaction_time

Выход:

transaction_time  item  quantity  subtotal
----------------------------------------------
15.05.2012        A     30        60
10.06.2012        A     45        90
15.06.2012        A     40        80

Демо здесь

Другие вопросы по теме