SQL 比较由 space 分隔的值
SQL to compare values separated by space
亲爱的,
我的 oracle table 中有如下值:
值由 space 分隔。我需要检查 value1 列中存在的所有值是否都存在于 value2 中。如果是,请将 isMatch 更新为 'Y'.
我可以通过 PLSQL 做到这一点,因为我的 table 包含 200 万条记录,这需要很多时间。
这可以通过 SQL 完成吗?
------ padaleiana 的回答更新----
请在下面找到解释计划:
我添加了 /*+ ORDERED USE_HASH(b) append */ 提示以及在 value1 和 value2 上创建索引,但成本仍然太高。
谢谢。
也许有更好和更优化的解决方案,但一个解决方案可能是下面的(假设您的 table 被称为 table1
):
MERGE INTO table1 t1
USING table1 t2 ON (regexp_count(t2.value1, replace(t1.value1, ' ', '|')) =
regexp_count(t1.value2, replace(t1.value1, ' ', '|')))
WHEN MATCHED THEN
UPDATE SET t1.isMatch = 'Y';
MERGE
command 就像 upsert。在这种情况下,您只需要使用 WHEN MATCHED THEN...
,因为如果找不到匹配的行,您不想插入新值。
REGEXP_COUNT
表示某个模式在字符串中出现的次数。这里,模式是 replace(t1.value1, ' ', '|')
(用 |
替换空格),字符串是 t1.value1
.
这里是demo.
每个值列都可以单独拆分、排序,然后合并。在连接过程中,通过与原始 table 的每个 ID 值的最大数量的不同拾取片段进行比较,检查每个拆分片段的相等性。因此,使用以下查询:
WITH t1 AS
(
SELECT DISTINCT ID, REGEXP_SUBSTR(value1,'[^ ]+',1,level) AS value1, level AS cnt
FROM t -- original table
CONNECT BY level <= REGEXP_COUNT(value1,' ') + 1
AND PRIOR SYS_GUID() IS NOT NULL
AND PRIOR ID = ID
ORDER BY value1
), t2 AS
(
SELECT DISTINCT ID, REGEXP_SUBSTR(value2,'[^ ]+',1,level) AS value2, level AS cnt
FROM t
CONNECT BY level <= REGEXP_COUNT(value2,' ') + 1
AND PRIOR SYS_GUID() IS NOT NULL
AND PRIOR ID = ID
ORDER BY value2
)
SELECT DISTINCT t.*,
CASE WHEN SUM(CASE WHEN t1.value1 = t2.value2 THEN 1 END) OVER (PARTITION BY t.ID)
= MAX(t1.cnt) OVER (PARTITION BY t.ID)
THEN
'Y'
ELSE
'N'
END AS ismatch
FROM t
LEFT JOIN t1
ON t1.ID = t.ID
LEFT JOIN t2
ON t2.ID = t1.ID
AND t1.value1 = t2.value2
ORDER BY t.ID;
亲爱的,
我的 oracle table 中有如下值:
值由 space 分隔。我需要检查 value1 列中存在的所有值是否都存在于 value2 中。如果是,请将 isMatch 更新为 'Y'.
我可以通过 PLSQL 做到这一点,因为我的 table 包含 200 万条记录,这需要很多时间。
这可以通过 SQL 完成吗?
------ padaleiana 的回答更新----
请在下面找到解释计划:
我添加了 /*+ ORDERED USE_HASH(b) append */ 提示以及在 value1 和 value2 上创建索引,但成本仍然太高。
谢谢。
也许有更好和更优化的解决方案,但一个解决方案可能是下面的(假设您的 table 被称为 table1
):
MERGE INTO table1 t1
USING table1 t2 ON (regexp_count(t2.value1, replace(t1.value1, ' ', '|')) =
regexp_count(t1.value2, replace(t1.value1, ' ', '|')))
WHEN MATCHED THEN
UPDATE SET t1.isMatch = 'Y';
MERGE
command 就像 upsert。在这种情况下,您只需要使用 WHEN MATCHED THEN...
,因为如果找不到匹配的行,您不想插入新值。
REGEXP_COUNT
表示某个模式在字符串中出现的次数。这里,模式是 replace(t1.value1, ' ', '|')
(用 |
替换空格),字符串是 t1.value1
.
这里是demo.
每个值列都可以单独拆分、排序,然后合并。在连接过程中,通过与原始 table 的每个 ID 值的最大数量的不同拾取片段进行比较,检查每个拆分片段的相等性。因此,使用以下查询:
WITH t1 AS
(
SELECT DISTINCT ID, REGEXP_SUBSTR(value1,'[^ ]+',1,level) AS value1, level AS cnt
FROM t -- original table
CONNECT BY level <= REGEXP_COUNT(value1,' ') + 1
AND PRIOR SYS_GUID() IS NOT NULL
AND PRIOR ID = ID
ORDER BY value1
), t2 AS
(
SELECT DISTINCT ID, REGEXP_SUBSTR(value2,'[^ ]+',1,level) AS value2, level AS cnt
FROM t
CONNECT BY level <= REGEXP_COUNT(value2,' ') + 1
AND PRIOR SYS_GUID() IS NOT NULL
AND PRIOR ID = ID
ORDER BY value2
)
SELECT DISTINCT t.*,
CASE WHEN SUM(CASE WHEN t1.value1 = t2.value2 THEN 1 END) OVER (PARTITION BY t.ID)
= MAX(t1.cnt) OVER (PARTITION BY t.ID)
THEN
'Y'
ELSE
'N'
END AS ismatch
FROM t
LEFT JOIN t1
ON t1.ID = t.ID
LEFT JOIN t2
ON t2.ID = t1.ID
AND t1.value1 = t2.value2
ORDER BY t.ID;