Postgresql Среднее время прохождения 5000 миль для расчета следующей замены масла - PullRequest
0 голосов
/ 12 июля 2011

Допустим, у меня есть две таблицы.

Таблица 1: service_sales_closed

Таблица 2: service_sales_details

service_sales_closed:

ronumber - Repair Order Number
custno - Customer Number
closedate - Closed RO Date
mileage - Mileage
vehid - VIN

service_sales_details:

ronumber
opcode - Operation Code (What type of repair)

Что я хотел бы сделать:

Для каждого автомобиля по определенному номеру (скажем, его замена масла) Сколько времени потребуется этому транспортному средству, чтобы проехать около 5000 миль .Затем, если возможно, в сегодняшнюю дату (или вчера) можно будет определить, должна ли эта машина заменить масло в течение следующей недели или около того, исходя из того, сколько времени потребуется этому автомобилю, чтобы проехать 5000 миль.Мне нужно убедиться, что они недавно не пришли на замену масла , хотя это может быть сведено на нет из-за интеллекта выбора.

У меня есть следующее, чтобы определить замену маслана основе 23-30дней с момента замены автомобиля:

   SELECT <*noted fields*>
     FROM service_sales_closed
LEFT JOIN service_sales_details ON service_sales_closed.ronumber = service_sales_details.ronumber
LEFT JOIN vehicle ON servicesalesclosed.vehid = vehicle.vehid
    WHERE service_sales_closed.closedate >= current_date - integer '90' 
      AND service_sales_closed.closedate <= current_date - integer '83' 
      AND service_sales_details.opcode = '04DOZ1' 
      AND service_sales_closed.vehid NOT IN (SELECT service_sales_closed.vehid
                                               FROM service_sales_closed
                                          LEFT JOIN service_sales_details ON service_sales_closed.ronumber = service_sales_details.ronumber
                                              WHERE service_sales_closed.closedate > current_date - integer '83' 
                                                AND service_sales_details.opcode = 'oilchange')

1 Ответ

1 голос
/ 12 июля 2011

сколько времени потребуется этому автомобилю, чтобы проехать около 5000 миль

Ну, я думаю, это главная проблема.

Откуда взялись "5000 миль"?Это ваш рекомендуемый интервал между заменами масла?Возможно, вы захотите запланировать другие операции обслуживания, которые происходят через разные промежутки времени (шины, что угодно).Так что вам нужен способ кодировать эти интервалы.

Я приведу небольшой пример:

CREATE TABLE service_types (
  st_id SERIAL PRIMARY KEY, 
  st_name TEXT, 
  st_interval_miles INTEGER, 
  st_interval_time INTERVAL
);

CREATE TABLE vehicles ( veh_id SERIAL PRIMARY KEY, birth_date DATE );

CREATE TABLE service_sales ( 
 ss_id SERIAL PRIMARY KEY, 
 ss_mileage INTEGER NOT NULL,
 ss_date DATE NOT NULL,
 veh_id INTEGER NOT NULL REFERENCES vehicles( veh_id )
);

CREATE TABLE service_details( 
 ss_id INTEGER NOT NULL REFERENCES service_sales( ss_id ),
 st_id INTEGER NOT NULL REFERENCES service_types( st_id )
);

Давайте заполним это:

INSERT INTO service_types (st_name,st_interval_miles,st_interval_time) VALUES
('oil change', 5000, '2 YEAR'),
('timing belt', 60000, '5 YEAR');

INSERT INTO vehicles (veh_id,birth_date) VALUES (1,'2009-09-01'),(2,'2009-08-01');

INSERT INTO service_sales (ss_id, veh_id, ss_mileage, ss_date) VALUES
(1, 1, 5000,  '2010-01-01'),
(2, 1, 12000, '2010-04-01'),
(3, 1, 18000, '2010-09-01'),
(4, 2, 5000,  '2010-01-01'),
(5, 2, 10000, '2010-08-01'),
(6, 2, 16000, '2010-12-01');

INSERT INTO service_details (ss_id,st_id) VALUES
(1,1),
(2,1),
(3,1),
(4,1),
(5,1),
(6,1);

SELECT * FROM vehicles v
JOIN service_sales USING (veh_id)
JOIN service_details USING (ss_id)
JOIN service_types USING (st_id);

 st_id | ss_id | veh_id | birth_date | ss_mileage |  ss_date   |  st_name   | st_interval_miles | st_interval_time 
-------+-------+--------+------------+------------+------------+------------+-------------------+------------------
     1 |     1 |      1 | 2009-09-01 |       5000 | 2010-01-01 | oil change |              5000 | 2 years
     1 |     2 |      1 | 2009-09-01 |      12000 | 2010-04-01 | oil change |              5000 | 2 years
     1 |     3 |      1 | 2009-09-01 |      18000 | 2010-09-01 | oil change |              5000 | 2 years
     1 |     4 |      2 | 2009-08-01 |       5000 | 2010-01-01 | oil change |              5000 | 2 years
     1 |     5 |      2 | 2009-08-01 |      10000 | 2010-08-01 | oil change |              5000 | 2 years
     1 |     6 |      2 | 2009-08-01 |      16000 | 2010-12-01 | oil change |              5000 | 2 years

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

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

Допустим, вы оцените среднюю скорость по всемраз ваш магазин увидел этот автомобиль.

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

SELECT foo.veh_id, 
(last.ss_mileage-first.ss_mileage) AS miles, 
(last.ss_date-first.ss_date) AS days FROM (
 SELECT veh_id, min( ss_id ) AS first_ss_id, max( ss_id ) AS last_ss_id 
 FROM service_sales GROUP BY veh_id
) foo 
JOIN service_sales first ON (first.ss_id=first_ss_id) 
JOIN service_sales last ON (last.ss_id=last_ss_id)
WHERE first_ss_id != last_ss_id AND last.ss_date <= first.ss_date + '1 WEEK'::INTERVAL;
 veh_id | miles | days 
--------+-------+------
      1 | 13000 |  243
      2 | 11000 |  334

Таким образом, мы знаем, сколько миль было пройдено каждым транспортным средством за сколько дней.Условие WHERE исключает транспортные средства, которые имеют только одну служебную запись или о которых ваш магазин знает только менее чем за 1 неделю, что не дает очень хорошей оценки.Вы можете использовать LEFT JOIN и некоторую работу COALESCE, чтобы заменить это ненадежным значением по умолчанию.

Теперь из последней замены масла и средней скорости мы можем получить значение для следующей замены масла:

WITH 
avgspeeds AS (SELECT foo.veh_id, 
    (last.ss_mileage-first.ss_mileage) AS miles, 
    (last.ss_date-first.ss_date) AS days FROM (
     SELECT veh_id, min( ss_id ) AS first_ss_id, max( ss_id ) AS last_ss_id 
     FROM service_sales GROUP BY veh_id
        ) foo 
    JOIN service_sales first ON (first.ss_id=first_ss_id) 
    JOIN service_sales last ON (last.ss_id=last_ss_id)
    WHERE first_ss_id != last_ss_id AND last.ss_date >= first.ss_date + '1 WEEK'::INTERVAL
),

last_services AS (SELECT 
 veh_id, 
     st_id, 
 max(ss_date) AS last_service_date
FROM service_sales
JOIN service_details USING (ss_id)
GROUP BY veh_id, st_id)

SELECT *,
  COALESCE( last_service_date, birth_date ) + least(
     (st.st_interval_miles * a.days / a.miles) * '1 DAY'::INTERVAL,
     st.st_interval_time) AS next_service_date
FROM
service_types st
CROSS JOIN vehicles v
JOIN avgspeeds a USING (veh_id)
LEFT JOIN last_services ls USING (veh_id,st_id);

Монстр, а?Кажется, дает правильные результаты.

Удачи;)

Почему вы ставите ненужные префиксы перед каждым именем столбца?Я действительно ненавижу, когда люди делают это, это делает каждый запрос чертовски уродливым,

Потому что: - Это делает запросы читабельными - я ненавижу иметь несколько полей "id" в наборах результатов, поступающих из любоготаблицы - Внешние ключи должны иметь одинаковые имена в обеих таблицах, что позволяет использовать NATURAL JOIN и очень полезное JOIN .. ИСПОЛЬЗОВАНИЕ - Мне все равно, что вам это не понравится

иэто еще хуже, если вы используете Orm.Псевдоним столбца уже в стандарте sql, используйте его

Если ваш ORM не позволяет вам определять имена столбцов таблицы, которые отличаются от имен членов объекта, и писать большие (но читабельные) запросы SQLвам нужен настоящий ORM.

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