powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Прошу помочь разобраться.
11 сообщений из 11, страница 1 из 1
Прошу помочь разобраться.
    #39506335
loisop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Прошу помочь разобраться в составлении запроса. Перерыл уже весь инет (ну, не весь, но полрунета точно).
Имеется таблица:
id
uY Год
uM Месяц
a_id ИД авто
fin_km Показания спидометра на последний день месяца

Хочу получить пробег всех машин за произвольный месяц.
Но есть моменты:
1) переход через НГ,
2) машина может простоять месяц-другой-третий..

Пока вымучил из себя вотт такой запрос:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
SELECT  * , min(delta) FROM (
SELECT
     b.a_id,
     b.uY bduy, b.uM bdum,
     a.uY aduy, a.uM adum,
 (b.uY*12 + b.uM  - a.uY*12 - a.uM) delta,
     b.fin_km bdfk, a.fin_km adfk,
     b.fin_km- a.fin_km probeg
  FROM rashod as a
   JOIN rashod as b ON  (b.a_id = a.a_id)
 ) as d
 WHERE bdum = 8 AND delta >0
 GROUP BY a_id



Но запрос работает не верно, выбирает первую, а не предыдущую. ((
Просьба натыкать, где я ошибся.
...
Рейтинг: 0 / 0
Прошу помочь разобраться.
    #39506366
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
loisopесть моменты:
1) переход через НГ,
В принципе не влияет.

loisop2) машина может простоять месяц-другой-третий..
И что? за соответствующий месяц запись отсутствует? или как?
Продемонстрируйте свои данные не описанием "на пальцах", а набором запросов CREATE TABLE + INSERT INTO. Запросы - проверить!!! а то бывали тут ... авторы - постили нерабочие или кривые запросы. Ну и предусмотрите в данных ВСЕ возможные "моменты" - и для каждого укажите входные параметры плюс желаемый результат с пояснением, почему именно так.
...
Рейтинг: 0 / 0
Прошу помочь разобраться.
    #39506375
loisop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Akina,


AkinaИ что? за соответствующий месяц запись отсутствует? или как?

Да, если движухи нет - данные не вносятся.


AkinaПродемонстрируйте свои данные не описанием "на пальцах", а набором запросов CREATE TABLE + INSERT INTO.


Колонка Тип Комментарий
id int(3) Автоматическое приращение
uY int(4) [2017]
uM int(2)
a_id int(2)
fin_km int(8)

Индексы
PRIMARY id
INDEX a_id


INSERT INTO `rashod` (`id`, `uY`, `uM`, `a_id`, `fin_km`) VALUES
(1, 2016, 12, 1, 375899),
(2, 2016, 12, 2, 300077),
(3, 2016, 12, 3, 122794),
(4, 2017, 1, 1, 391199),
(5, 2017, 1, 2, 316577),
(6, 2017, 2, 1, 422199),
(7, 2017, 3, 1, 451899),
(8, 2017, 8, 3, 129694),
(12, 2017, 8, 1, 542838),
(13, 2017, 1, 3, 124194);

Вышеуказанный запрос дает такое:


a_id bduy bdum aduy adum delta bdfk adfk probeg min(delta)
1 2017 8 2016 12 8 542838 375899 166939 5
3 2017 8 2016 12 8 129694 122794 6900 7
...
Рейтинг: 0 / 0
Прошу помочь разобраться.
    #39506380
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А где CREATE TABLE?

loisopВышеуказанный запрос дает такоеНу вот кому интересно, что даёт неправильный запрос?
Лучше было сформулировать задачу (например, "найти пробег за 25 месяц 2345 года"), эталонный ответ (например, "125") и пояснение (например, "за 25-2345 пробег 1000, предыдущее значение 750, но за 23-2345, так что это 2 месяца, разность делим на 2, получаем 125").
...
Рейтинг: 0 / 0
Прошу помочь разобраться.
    #39506381
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Соответственно рассмотреть ВСЕ варианты задач (есть за этот и предыдущий, есть за этот и нет за предыдущий, есть за следующий/предыдущий и нет за этот, есть за этот и вообще нет записей раньше, и т.п.), каждая со своими исходными на ЭТИХ данных.
...
Рейтинг: 0 / 0
Прошу помочь разобраться.
    #39506403
loisop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
AkinaА где CREATE TABLE?

Извиняюсь..

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
DROP TABLE IF EXISTS `rashod`;
CREATE TABLE `rashod` (
  `id` int(3) NOT NULL AUTO_INCREMENT,
  `uY` int(4) NOT NULL DEFAULT '2017',
  `uM` int(2) NOT NULL,
  `a_id` int(2) NOT NULL,
  `beg_km` int(8) NOT NULL,
  `fin_km` int(8) NOT NULL,
  `beg_fuel` float NOT NULL,
  `buy_fuel_cash` float NOT NULL,
  `buy_fuel_card` float NOT NULL,
  PRIMARY KEY (`id`),
  KEY `a_id` (`a_id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;




AkinaЛучше было сформулировать задачу (например, "найти пробег за 25 месяц 2345 года"), эталонный ответ (например, "125") и пояснение (например, "за 25-2345 пробег 1000, предыдущее значение 750, но за 23-2345, так что это 2 месяца, разность делим на 2, получаем 125").

Найти пробег каждой машины за (например) 8й месяц 2017 года. Должно получиться примерно так (цифры пробега "с потолка"):

a_id probeg
1 10639
2 47930
3 0
4 0
5 6907

Для 1,2 и 5 машин пробег = разница с предыдущим показателем (который может быть и старше 1 месяца).
Для 3 и 4 машин пробег нулевой потому, что данных выбранного месяца нет.


AkinaСоответственно рассмотреть ВСЕ варианты задач (есть за этот и предыдущий, есть за этот и нет за предыдущий, есть за следующий/предыдущий и нет за этот, есть за этот и вообще нет записей раньше, и т.п.), каждая со своими исходными на ЭТИХ данных.

Варианты.
1. Есть данные за указанный И есть за непосредственно предыдущий месяц: пробег = разница с предыдущим показателем (машина в работе)
2. Есть данные за указанный И есть за предыдущий (с неким, большим 1, интервалом) месяц: пробег = разница с предыдущим показателем (машина простаивала)
3. Есть данные за указанный И нет данных за любой предыдущий месяц: пробег = указанный показатель (условно, вариант "новая машина")
4. Нет данных за указанный И есть за любой предыдущий месяцы: пробег нулевой (машина в простое)

С конкретными цифрами быстро не могу (могу перебить исходные данные, на более легкие, и тогда уже дать).
...
Рейтинг: 0 / 0
Прошу помочь разобраться.
    #39506430
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Уже лучше... но приведённый выше код вставки данных не лезет в опубликованный DDL... хотя я просил ПРОВЕРИТЬ работоспособность...

Пока теоретически: придётся получать данные в три этапа.
1) Получить список машин.
2) Получить пробег на заданный месяц, для отсутствующих - ноль.
3) Получить пробег на последний ранее заданного месяц, для отсутствующих - ноль.
Вычитание даст пробег за заданный месяц.
...
Рейтинг: 0 / 0
Прошу помочь разобраться.
    #39506457
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
CREATE TABLE data (
car INT,
km INT,
y INT,
m INT
);

-- Месяц для поиска
SET @y = 2016;
SET @m = 8;

-- Тест-данные
INSERT INTO data (car,km,y,m)
-- есть за текущий и предыдущий месяцы, результат = 1
SELECT 1,1,2016,7 UNION ALL
SELECT 1,2,2016,8 UNION ALL
-- есть за текущий и на 2 месяца раньше, результат = 11
SELECT 2,11,2016,6 UNION ALL
SELECT 2,22,2016,8 UNION ALL
-- есть за текущий, нет раньше, результат = 33
SELECT 3,33,2016,8 UNION ALL
-- нет за текущий, есть раньше, результат = 0
SELECT 4,44,2016,7 ;

CREATE VIEW cars AS -- список машин
SELECT DISTINCT car FROM data;

SELECT * FROM cars; -- проверка

CREATE VIEW current_km AS -- пробег на текущий месяц
SELECT cars.car, COALESCE(data.km,0) km
FROM cars
LEFT JOIN data 
ON cars.car = data.car
AND data.y = /* @y */ 2016 AND data.m = /* @m */ 8;

SELECT * FROM current_km; -- проверка

CREATE VIEW prev_ym AS -- предыдущие год и месяц с показаниями
SELECT car, MAX(data.y * 12 + data.m) ym
FROM data
WHERE (data.y * 12 + data.m) < (/* @y */ 2016 * 12 + /* @m */ 8)
GROUP BY car;

SELECT * FROM prev_ym; -- проверка

CREATE VIEW prev_km AS -- предыдущий пробег
SELECT DISTINCT cars.car, COALESCE(data.km,0) km
FROM cars
LEFT JOIN (data 
           JOIN prev_ym ON (data.y * 12 + data.m) = prev_ym.ym
          ) ON cars.car = data.car;

SELECT * FROM prev_km; -- проверка

-- Получаем итоги
SELECT cars.car, GREATEST(current_km.km - prev_km.km, 0) km
FROM cars 
JOIN current_km ON cars.car = current_km.car
JOIN prev_km ON cars.car = prev_km.car;

-- Сборка в один запрос

SELECT cars.car, GREATEST(current_km.km - prev_km.km, 0) km
FROM (SELECT DISTINCT car FROM data) cars 
JOIN (
		SELECT cars.car, COALESCE(data.km,0) km
		FROM (SELECT DISTINCT car FROM data) cars
		LEFT JOIN data 
		ON cars.car = data.car
		AND data.y = @y AND data.m = @m
	 ) current_km ON cars.car = current_km.car
JOIN (
		SELECT DISTINCT cars.car, COALESCE(data.km,0) km
		FROM (SELECT DISTINCT car FROM data) cars
		LEFT JOIN (data 
				   JOIN (
							SELECT car, MAX(data.y * 12 + data.m) ym
							FROM data
							WHERE (data.y * 12 + data.m) < (@y * 12 + @m)
							GROUP BY car				   
				        ) prev_ym ON (data.y * 12 + data.m) = prev_ym.ym
				  ) ON cars.car = data.car
     ) prev_km ON cars.car = prev_km.car;


-- Очистка
DROP VIEW prev_km;
DROP VIEW prev_ym;
DROP VIEW current_km;
DROP VIEW cars;
DROP TABLE data;

...
Рейтинг: 0 / 0
Прошу помочь разобраться.
    #39506956
loisop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Akina,

Вчера не смог отреагировать на сообщение. Спасибо за приведенный код.
К сожалению, он (код) не совсем рабочий.. Сегодня убил почти весь день, пытаясь исправить. На текущий момент, увы..
Ваш код работает, если значений всего 2, за текущий месяц и за произвольно предыдущий. Если значений больше (а предполагается, что таки будет больше), то идет удвоение вывода с разными значениями пробега: разницы нужного с предыдущим И разница нужного с первым.

Приведу Ваш код, с добавленными данными:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
CREATE TABLE data (
car INT,
km INT,
y INT,
m INT
);

-- Месяц для поиска
SET @y = 2016;
SET @m = 8;

-- Тест-данные
INSERT INTO data (car,km,y,m)
-- есть за текущий и предыдущий месяцы, результат = 1
SELECT 1,1,2016,6 UNION ALL
SELECT 1,4,2016,7 UNION ALL
SELECT 1,5,2016,8 UNION ALL
-- есть за текущий и на 2 месяца раньше, результат = 11
SELECT 2,11,2016,1 UNION ALL
SELECT 2,16,2016,6 UNION ALL
SELECT 2,22,2016,8 UNION ALL
-- есть за текущий, нет раньше, результат = 33
SELECT 3,33,2016,8 UNION ALL
-- нет за текущий, есть раньше, результат = 0
SELECT 4,44,2016,1 ;
SELECT 4,47,2016,2 ;
SELECT 4,51,2016,3 ;
SELECT 4,56,2016,4 ;

CREATE VIEW cars AS -- список машин
SELECT DISTINCT car FROM data;

SELECT * FROM cars; -- проверка

CREATE VIEW current_km AS -- пробег на текущий месяц
SELECT cars.car, COALESCE(data.km,0) km
FROM cars
LEFT JOIN data 
ON cars.car = data.car
AND data.y = /* @y */ 2016 AND data.m = /* @m */ 8;

SELECT * FROM current_km; -- проверка

CREATE VIEW prev_ym AS -- предыдущие год и месяц с показаниями
SELECT car, MAX(data.y * 12 + data.m) ym
FROM data
WHERE (data.y * 12 + data.m) < (/* @y */ 2016 * 12 + /* @m */ 8)
GROUP BY car;

SELECT * FROM prev_ym; -- проверка

CREATE VIEW prev_km AS -- предыдущий пробег
SELECT DISTINCT cars.car, COALESCE(data.km,0) km
FROM cars
LEFT JOIN (data 
           JOIN prev_ym ON (data.y * 12 + data.m) = prev_ym.ym
          ) ON cars.car = data.car;

SELECT * FROM prev_km; -- проверка

-- Получаем итоги
SELECT cars.car, GREATEST(current_km.km - prev_km.km, 0) km
FROM cars 
JOIN current_km ON cars.car = current_km.car
JOIN prev_km ON cars.car = prev_km.car;

-- Сборка в один запрос

SELECT cars.car, GREATEST(current_km.km - prev_km.km, 0) km
FROM (SELECT DISTINCT car FROM data) cars 
JOIN (
		SELECT cars.car, COALESCE(data.km,0) km
		FROM (SELECT DISTINCT car FROM data) cars
		LEFT JOIN data 
		ON cars.car = data.car
		AND data.y = @y AND data.m = @m
	 ) current_km ON cars.car = current_km.car
JOIN (
		SELECT DISTINCT cars.car, COALESCE(data.km,0) km
		FROM (SELECT DISTINCT car FROM data) cars
		LEFT JOIN (data 
				   JOIN (
							SELECT car, MAX(data.y * 12 + data.m) ym
							FROM data
							WHERE (data.y * 12 + data.m) < (@y * 12 + @m)
							GROUP BY car				   
				        ) prev_ym ON (data.y * 12 + data.m) = prev_ym.ym
				  ) ON cars.car = data.car
     ) prev_km ON cars.car = prev_km.car;


-- Очистка
DROP VIEW prev_km;
DROP VIEW prev_ym;
DROP VIEW current_km;
DROP VIEW cars;
DROP TABLE data;
...
Рейтинг: 0 / 0
Прошу помочь разобраться.
    #39507011
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
loisopСегодня убил почти весь день, пытаясь исправить.
Что тут делать целый день? При прогоне ведь сразу видно, что неверные результаты получаются на этапе получения предыдущего пробега.
Если выполнить запрос этой вьюшки, выведя все дополнительные поля
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
mysql> SELECT DISTINCT cars.car, COALESCE(data.km,0) km, cars.*, data.*, prev_ym.*
    -> FROM cars
    -> LEFT JOIN (data
    ->            JOIN prev_ym ON (data.y * 12 + data.m) = prev_ym.ym
    ->           ) ON cars.car = data.car;
+------+------+------+------+------+------+------+------+-------+
| car  | km   | car  | car  | km   | y    | m    | car  | ym    |
+------+------+------+------+------+------+------+------+-------+
|    1 |    4 |    1 |    1 |    4 | 2016 |    7 |    1 | 24199 |
|    1 |    1 |    1 |    1 |    1 | 2016 |    6 |    2 | 24198 |
|    2 |   16 |    2 |    2 |   16 | 2016 |    6 |    2 | 24198 |
|    4 |   56 |    4 |    4 |   56 | 2016 |    4 |    4 | 24196 |
|    3 |    0 |    3 | NULL | NULL | NULL | NULL | NULL |  NULL |
+------+------+------+------+------+------+------+------+-------+

то сразу становится видна причина - рассогласование между data.car и prev_ym.car.
Добавим соответствующее условие:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
mysql> SELECT DISTINCT cars.car, COALESCE(data.km,0) km, cars.*, data.*, prev_ym.*
    -> FROM cars
    -> LEFT JOIN (data
    ->            JOIN prev_ym ON (data.y * 12 + data.m) = prev_ym.ym
    ->                        AND data.car = prev_ym.car
    ->           ) ON cars.car = data.car;
+------+------+------+------+------+------+------+------+-------+
| car  | km   | car  | car  | km   | y    | m    | car  | ym    |
+------+------+------+------+------+------+------+------+-------+
|    1 |    4 |    1 |    1 |    4 | 2016 |    7 |    1 | 24199 |
|    2 |   16 |    2 |    2 |   16 | 2016 |    6 |    2 | 24198 |
|    3 |    0 |    3 | NULL | NULL | NULL | NULL | NULL |  NULL |
|    4 |   56 |    4 |    4 |   56 | 2016 |    4 |    4 | 24196 |
+------+------+------+------+------+------+------+------+-------+
4 rows in set (0.00 sec)


Вот, теперь лучше... осталось внести это исправление в окончательный запрос и убедиться, что результат соответствует истинному:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
mysql> SELECT cars.car, GREATEST(current_km.km - prev_km.km, 0) km
    -> FROM (SELECT DISTINCT car FROM data) cars
    -> JOIN (
    ->          SELECT cars.car, COALESCE(data.km,0) km
    ->          FROM (SELECT DISTINCT car FROM data) cars
    ->          LEFT JOIN data
    ->          ON cars.car = data.car
    ->          AND data.y = @y AND data.m = @m
    ->   ) current_km ON cars.car = current_km.car
    -> JOIN (
    ->          SELECT DISTINCT cars.car, COALESCE(data.km,0) km
    ->          FROM (SELECT DISTINCT car FROM data) cars
    ->          LEFT JOIN (data
    ->                             JOIN (
    ->                                                  SELECT car, MAX(data.y * 12 + data.m) ym
    ->                                                  FROM data
    ->                                                  WHERE (data.y * 12 + data.m) < (@y * 12 + @m)
    ->                                                  GROUP BY car
    ->                                  ) prev_ym ON (data.y * 12 + data.m) = prev_ym.ym
    ->                                           AND data.car = prev_ym.car
    ->                            ) ON cars.car = data.car
    ->      ) prev_km ON cars.car = prev_km.car;
+------+------+
| car  | km   |
+------+------+
|    1 |    1 |
|    2 |    6 |
|    3 |   33 |
|    4 |    0 |
+------+------+
4 rows in set (0.00 sec)
...
Рейтинг: 0 / 0
Прошу помочь разобраться.
    #39507241
loisop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Akina,

Не знаю, как выразить благодарность за код и, в особенности, за разъяснения!
...
Рейтинг: 0 / 0
11 сообщений из 11, страница 1 из 1
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Прошу помочь разобраться.
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]