Oracle select 相似值
Oracle select similar values
我有一个数据库 table 有很多这样的值:340.13 和 232.89。
现在我想select与比较值最匹配的值。
不费吹灰之力就可以做到吗?
这将匹配搜索值 +-10% 范围内的值,如果有多个值,将根据绝对差异找到最接近的匹配项。
Oracle 11g R2 模式设置:
CREATE TABLE TABLE_NAME ( VALUE ) AS
SELECT 340.13 FROM DUAL UNION ALL
SELECT 232.89 FROM DUAL UNION ALL
SELECT 224.73 FROM DUAL UNION ALL
SELECT 100.00 FROM DUAL;
查询 1:
WITH search_values ( search_value ) AS (
SELECT 330 FROM DUAL UNION ALL
SELECT 230 FROM DUAL
)
SELECT search_value,
value
FROM (
SELECT search_value,
value,
RANK() OVER ( PARTITION BY Search_value
ORDER BY ABS( value - search_value ) ) AS rnk
FROM table_name t
INNER JOIN
search_values v
ON ( t.value BETWEEN search_value * 0.9 AND search_value * 1.1 )
)
WHERE Rnk = 1
| SEARCH_VALUE | VALUE |
|--------------|--------|
| 230 | 232.89 |
| 330 | 340.13 |
这是一个非常基本和常见的任务,所以这里是一般方法。
首先你需要决定"best-match-criteria"。基本上它作为存储在行和输入值中的值的函数。所以你可以实现这个函数并评估它,为每一行调用类似 MATCH_RATING(COLUMN, :value)
的东西。现在你对每一行都有这个 rating,你可以按照你喜欢的任何方式对行进行排序并过滤最合适的行(ROWNUM
非常适合这个,分析函数也是如此RANK
或 ROW_NUMBER
).
SELECT *
FROM (
SELECT VALUE,
MATCH_RATING(VALUE, :input_value) RATING
FROM YOUR_TABLE
ORDER BY RATING DESC)
WHERE ROWNUM = 1
那么一个好主意是检查您选择的标准是否以语言实现,因为如果是,使用 SQL 功能肯定会在性能方面更好。
例如,如果两个数字之间的距离是您唯一关心的事情,SQL 将看起来像这样。
SELECT VALUE
FROM (
SELECT VALUE,
ABS(VALUE - :input_value) DISTANCE
FROM YOUR_TABLE
ORDER BY DISTANCE)
WHERE ROWNUM = 1
如果您的 函数 在某个时间间隔内假定值为 0,这意味着某些行永远不会进入您的结果集,那么您还应该使用 WHERE
子句过滤无用的行(WHERE MATCH_RATING(COLUMN, :value) > 0
).
回到我们的距离示例:让我们接受距离不超过输入值的 5%。
SELECT VALUE
FROM (
SELECT VALUE,
ABS(VALUE - :input_value) DISTANCE
FROM YOUR_TABLE
WHERE VALUE BETWEEN 0.95 * :input_value AND 1.05 * :input_value
ORDER BY DISTANCE)
WHERE ROWNUM = 1
顺便说一句,YOUR_TABLE.VALUE
上的索引肯定会对这个例子有所帮助。
我有一个数据库 table 有很多这样的值:340.13 和 232.89。
现在我想select与比较值最匹配的值。
不费吹灰之力就可以做到吗?
这将匹配搜索值 +-10% 范围内的值,如果有多个值,将根据绝对差异找到最接近的匹配项。
Oracle 11g R2 模式设置:
CREATE TABLE TABLE_NAME ( VALUE ) AS
SELECT 340.13 FROM DUAL UNION ALL
SELECT 232.89 FROM DUAL UNION ALL
SELECT 224.73 FROM DUAL UNION ALL
SELECT 100.00 FROM DUAL;
查询 1:
WITH search_values ( search_value ) AS (
SELECT 330 FROM DUAL UNION ALL
SELECT 230 FROM DUAL
)
SELECT search_value,
value
FROM (
SELECT search_value,
value,
RANK() OVER ( PARTITION BY Search_value
ORDER BY ABS( value - search_value ) ) AS rnk
FROM table_name t
INNER JOIN
search_values v
ON ( t.value BETWEEN search_value * 0.9 AND search_value * 1.1 )
)
WHERE Rnk = 1
| SEARCH_VALUE | VALUE |
|--------------|--------|
| 230 | 232.89 |
| 330 | 340.13 |
这是一个非常基本和常见的任务,所以这里是一般方法。
首先你需要决定"best-match-criteria"。基本上它作为存储在行和输入值中的值的函数。所以你可以实现这个函数并评估它,为每一行调用类似 MATCH_RATING(COLUMN, :value)
的东西。现在你对每一行都有这个 rating,你可以按照你喜欢的任何方式对行进行排序并过滤最合适的行(ROWNUM
非常适合这个,分析函数也是如此RANK
或 ROW_NUMBER
).
SELECT *
FROM (
SELECT VALUE,
MATCH_RATING(VALUE, :input_value) RATING
FROM YOUR_TABLE
ORDER BY RATING DESC)
WHERE ROWNUM = 1
那么一个好主意是检查您选择的标准是否以语言实现,因为如果是,使用 SQL 功能肯定会在性能方面更好。
例如,如果两个数字之间的距离是您唯一关心的事情,SQL 将看起来像这样。
SELECT VALUE
FROM (
SELECT VALUE,
ABS(VALUE - :input_value) DISTANCE
FROM YOUR_TABLE
ORDER BY DISTANCE)
WHERE ROWNUM = 1
如果您的 函数 在某个时间间隔内假定值为 0,这意味着某些行永远不会进入您的结果集,那么您还应该使用 WHERE
子句过滤无用的行(WHERE MATCH_RATING(COLUMN, :value) > 0
).
回到我们的距离示例:让我们接受距离不超过输入值的 5%。
SELECT VALUE
FROM (
SELECT VALUE,
ABS(VALUE - :input_value) DISTANCE
FROM YOUR_TABLE
WHERE VALUE BETWEEN 0.95 * :input_value AND 1.05 * :input_value
ORDER BY DISTANCE)
WHERE ROWNUM = 1
顺便说一句,YOUR_TABLE.VALUE
上的索引肯定会对这个例子有所帮助。