Найти ближайшее числовое значение в базе данных
Мне нужно найти инструкцию select, которая вернет либо запись, которая соответствует моему вводу, либо ближайшему совпадению, если точное совпадение не найдено.
Вот мой оператор выбора.
SELECT * FROM [myTable]
WHERE Name = 'Test' AND Size = 2 AND PType = 'p'
ORDER BY Area DESC
Мне нужно найти ближайшее соответствие к полю 'Area', поэтому, если мой ввод равен 1.125, а база данных содержит 2, 1.5, 1 и .5, запрос вернет запись, содержащую 1.
Мои навыки SQL очень ограничены, поэтому любая помощь будет оценена.
Ответы
Ответ 1
получить разницу между областью и вашим входом, принять абсолютное значение, всегда положительное, а затем упорядочить по возрастанию и взять первый
SELECT TOP 1 * FROM [myTable]
WHERE Name = 'Test' and Size = 2 and PType = 'p'
ORDER BY ABS( Area - @input )
Ответ 2
что-то ужасное, по строкам:
ORDER BY ABS( Area - 1.125 ) ASC LIMIT 1
Может быть,?
Ответ 3
Как насчет упорядочения по разнице между вашим входом и [Area], например:
DECLARE @InputValue DECIMAL(7, 3)
SET @InputValue = 1.125
SELECT TOP 1 * FROM [myTable]
WHERE Name = 'Test' AND Size = 2 AND PType = 'p'
ORDER BY ABS(@InputValue - Area)
Ответ 4
SELECT *
FROM [myTable]
WHERE Name = 'Test' AND Size = 2 AND PType = 'p'
ORDER BY ABS(Area - 1.125)
LIMIT 1
- MarkusQ
Ответ 5
Если у вас много строк, которые удовлетворяют предикатам равенства на столбцах Name
, Size
и PType
, то вы можете включить в предикат диапазона в столбце Area
в своем запросе. Если индекс Area
индексирован, это может обеспечить эффективный доступ на основе индексов.
Следующий запрос (написанный с использованием синтаксиса Oracle) использует одну ветвь UNION ALL
для поиска записи с минимальной Area >=
вашей целью, а другая ветка находит запись с максимальной Area <
вашей целью. Одной из этих двух записей будет запись, которую вы ищете. Тогда вы можете ORDER BY ABS(Area - ?input)
выбрать победителя из этих двух кандидатов. К сожалению, запрос сложный из-за вложенных SELECTS, которые необходимы для обеспечения желаемого приоритета ROWNUM/ORDER BY.
SELECT *
FROM
(SELECT * FROM
(SELECT * FROM
(SELECT * FROM [myTable]
WHERE Name = 'Test' AND Size = 2 AND PType = 'p' AND Area >= ?target
ORDER BY Area)
WHERE ROWNUM < 2
UNION ALL
SELECT * FROM
(SELECT * FROM [myTable]
WHERE Name = 'Test' AND Size = 2 AND PType = 'p' AND Area < ?target
ORDER BY Area DESC)
WHERE ROWNUM < 2)
ORDER BY ABS(Area - ?target))
WHERE rownum < 2
Хорошим индексом для этого запроса будет (Name, Size, PType, Area)
, и в этом случае ожидаемый план выполнения запроса будет основан на двух сканированиях диапазона индексов, каждый из которых возвращает одну строку.
Ответ 6
Обратите внимание, что хотя ABS() поддерживается почти всем, это не технически стандартно (по крайней мере, в SQL99). Если по какой-то причине вы должны написать стандартный SQL ANSI, вам придется обойти проблему с оператором CASE:
SELECT * FROM myTable
WHERE Name='Test' AND Size=2 AND PType='p'
ORDER BY CASE Area>1.125 WHEN 1 THEN Area-1.125 ELSE 1.125-Area END
Ответ 7
Если вы используете MySQL
SELECT * FROM [myTable] ... ORDER BY ABS(Area - SuppliedValue) LIMIT 1
Ответ 8
Выберите min, где [field] > your_target_value
Выберите max, где [поле] < your_target_value