powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Составить более оптимальный запрос (оптимизировать, предложить лучшее решение задачи)
6 сообщений из 6, страница 1 из 1
Составить более оптимальный запрос (оптимизировать, предложить лучшее решение задачи)
    #40116875
wlad1164
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Доброго времени суток!
Имеется 3 таблицы:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
CREATE TABLE IF NOT EXISTS `salestrk` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `obj` int(3) NOT NULL,
  `datetime` datetime NOT NULL,
  `np_code` int(10) NOT NULL,
  `np_article` int(10) NOT NULL,
  `trk` int(2) NOT NULL,
  `crane` int(1) NOT NULL,
  `count` decimal(8,3) NOT NULL,
  `sum` decimal(7,2) NOT NULL,
  `typecoin` text COLLATE utf8_unicode_ci NOT NULL,
  `checknum` text COLLATE utf8_unicode_ci NOT NULL,
  `checkdry` text COLLATE utf8_unicode_ci NOT NULL,
  `ordernum` text COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14419 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
CREATE TABLE IF NOT EXISTS `dpu` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `obj` int(11) NOT NULL,
  `datetime` datetime NOT NULL,
  `th_doc` text COLLATE utf8_unicode_ci NOT NULL,
  `docType` text COLLATE utf8_unicode_ci NOT NULL,
  `np_code` int(10) NOT NULL,
  `tank_code` int(10) NOT NULL,
  `lvl` decimal(5,1) NOT NULL,
  `value` decimal(8,3) NOT NULL,
  `temp` decimal(3,1) NOT NULL,
  `density` decimal(5,4) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=25486 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
CREATE TABLE IF NOT EXISTS `trk2tank` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `datetimeFrom` datetime NOT NULL,
  `obj` int(2) NOT NULL,
  `trk` int(2) NOT NULL,
  `crane` int(1) NOT NULL,
  `np_article` int(10) NOT NULL,
  `np_code` int(10) NOT NULL,
  `tank_number` int(2) NOT NULL,
  `tank_code` int(10) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=874 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;



Необходимо для каждой строки из salestrk (s) получить наибольшее по trk2tank.`datetimeFrom` значения trk2tank.`tank_number` и trk2tank.`tank_code` из таблицы trk2tank (t2) по условию, т.е.:
Код: sql
1.
t2.`obj`=s.`obj` AND t2.`crane`=s.`crane` AND t2.`trk`=s.`trk` AND t2.`datetimeFrom`<=s.`datetime` LIMIT 1



Затем для каждой строки из этой же таблицы (s) получить среднее значение между предыдущим и следующим по времени значениями `density` из таблицы dpu (d) по условиям (пример предыдущего, т.к. как вывести среднее двух не разобрался):
Код: sql
1.
WHERE 2.`obj`=s.`obj` AND 2.`tank_code`=t.`tank_code` AND 2.`datetime`<=s.`datetime` ORDER BY 2.`datetime` DESC LIMIT 1



В данный момент имею следующий запрос
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
SELECT s.`obj`,s.`datetime`,s.`np_code`,s.`trk`,s.`crane`, s.`count`, 
	t.`tank_number` AS 'T_tank_number', t.`tank_code` AS 'T_tank_code', t.`np_code` AS 'T_np_code',
	d.`density` AS 'D_density'

FROM `salestrk` s

LEFT JOIN `trk2tank` t
    ON t.`id`= (SELECT t2.`id` 
                FROM `trk2tank` t2
                WHERE t2.`obj`=s.`obj` AND t2.`crane`=s.`crane` AND t2.`trk`=s.`trk` AND t2.`datetimeFrom`<=s.`datetime` LIMIT 1)
LEFT JOIN `dpu` d
    ON d.`id`= (SELECT d2.`id` 
   				FROM `dpu` d2
                WHERE d2.`obj`=s.`obj` AND d2.`tank_code`=t.`tank_code` AND d2.`datetime`<=s.`datetime`
                ORDER BY d2.`datetime` DESC LIMIT 1)
WHERE s.`obj`=53



И исключая того что из dpu выводится только ближайшее предыдущее значение он работает. (Пробовал сделать еще один JOIN к этой же таблице, запрос выполняется наверное до истечения таймаута)
НО составлял я его по отрывкам из гугла, поэтому уверен что его нужно оптимизировать.
И требуется чтобы вместо ближайшего предыдущего, выводилось среднее между ближайшим предыдущим и ближайшим следующим.

В таблице salestrk содержится ~100 000 строк
В таблице dpu содержится ~1 000 000 строк
В таблице trk2tank содержится ~1 000 строк

Соответственно в таком виде запрос выполняется довольно долго.

Изменение структуры таблиц при необходимости допускается

Буду рад любой помощи.
в SQL не силен, прошу сильно не пинать)
...
Рейтинг: 0 / 0
Составить более оптимальный запрос (оптимизировать, предложить лучшее решение задачи)
    #40116878
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Точная версия MySQL?
...
Рейтинг: 0 / 0
Составить более оптимальный запрос (оптимизировать, предложить лучшее решение задачи)
    #40116879
wlad1164
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Akina,

Сервер: MySQL (127.0.0.1 via TCP/IP)
Тип сервера: MySQL
Версия сервера: 5.7.31 - MySQL Community Server (GPL)
...
Рейтинг: 0 / 0
Составить более оптимальный запрос (оптимизировать, предложить лучшее решение задачи)
    #40116909
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Тогда подзапрос для получения "наибольшего trk2tank.`datetimeFrom`", а далее по нему получение нужных данных из второй копии таблицы.
...
Рейтинг: 0 / 0
Составить более оптимальный запрос (оптимизировать, предложить лучшее решение задачи)
    #40116917
wlad1164
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Akina, т.е.
Код: sql
1.
2.
3.
4.
LEFT JOIN `trk2tank` t
    ON t.`id`= (SELECT t2.`id` 
                FROM `trk2tank` t2
                WHERE t2.`obj`=s.`obj` AND t2.`crane`=s.`crane` AND t2.`trk`=s.`trk` AND t2.`datetimeFrom`<=s.`datetime` LIMIT 1)


Можно считать оптимальным?

Подскажите по поводу среднего `density` из таблицы dpu, среднее как сумма ближайшего большего и меньшего по дате деленная на 2 и времени (в данный момент получаю только предыдущее)

в принципе запрос
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
SET @dt = '2021-10-12 10:15';

SELECT AVG(c.`density`)  AS 'DensityAB'
FROM (
    (SELECT `density` FROM `dpu` WHERE `obj`=53 AND `tank_code`=3600004 AND `datetime`<=@dt ORDER BY `datetime` DESC LIMIT 1) 
UNION ALL
	(SELECT `density` FROM `dpu` WHERE `obj`=53 AND `tank_code`=3600004 AND `datetime`>=@dt ORDER BY `datetime` ASC LIMIT 1) 
ORDER BY `density`) c;

делает это для фиксировано указанного obj, tank_code и datetime
Но как этот запрос "интегрировать" в первый не понимаю...
...
Рейтинг: 0 / 0
Составить более оптимальный запрос (оптимизировать, предложить лучшее решение задачи)
    #40116938
wlad1164
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Akina, с утра не понял о чем речь))
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
SELECT s0.*,
     # Получение среднего значения density из dpu (След+Превед/2)
    (
    (SELECT `density` FROM `dpu` 
     WHERE `obj`=s0.`obj` AND `tank_code`=s0.`T_tank_code` AND `datetime`<=s0.`datetime` ORDER BY `datetime` DESC LIMIT 1) 
    +
    (SELECT `density` FROM `dpu` 
     WHERE `obj`=s0.`obj` AND `tank_code`=s0.`T_tank_code` AND `datetime`>=s0.`datetime` ORDER BY `datetime` ASC LIMIT 1)
    )/ 2 AS 'DensityAVG' 
    
FROM
	# Таблица привязки tank_number и T_tank_code
	(SELECT s1.`obj`,s1.`datetime`,s1.`np_code`,s1.`trk`,s1.`crane`, s1.`count`, 
        t1.`tank_number` AS 'T_tank_number', t1.`tank_code` AS 'T_tank_code', t1.`np_code` AS 'T_np_code'
    FROM `salestrk` s1
    LEFT JOIN `trk2tank` t1
        ON t1.`id`= (SELECT t2.`id` 
                    FROM `trk2tank` t2
                    WHERE t2.`obj`=s1.`obj` AND t2.`crane`=s1.`crane` AND t2.`trk`=s1.`trk` 
                    	AND t2.`datetimeFrom`<=s1.`datetime` AND t2.`np_code` <> s1.`np_code` LIMIT 1)
    WHERE s1.`obj`=53) s0

Как более грамотно получить значение соответствующее выводу
Код: sql
1.
2.
3.
4.
5.
6.
7.
    (
    (SELECT `density` FROM `dpu` 
     WHERE `obj`=s0.`obj` AND `tank_code`=s0.`T_tank_code` AND `datetime`<=s0.`datetime` ORDER BY `datetime` DESC LIMIT 1) 
    +
    (SELECT `density` FROM `dpu` 
     WHERE `obj`=s0.`obj` AND `tank_code`=s0.`T_tank_code` AND `datetime`>=s0.`datetime` ORDER BY `datetime` ASC LIMIT 1)
    )/ 2 AS 'DensityAVG' 

?
Текущий вариант выглядит как минимум неказисто...

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


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