表FOO
的列FILEPATH
类型为VARCHAR(512)
。它的条目是绝对路径:
FILEPATH
------------------------------------------------------------
file://very/long/file/path/with/many/slashes/in/it/foo.xml
file://even/longer/file/path/with/more/slashes/in/it/baz.xml
file://something/completely/different/foo.xml
file://short/path/foobar.xml
此表中有大约50,000条记录,我想知道所有不同的文件名,而不是文件路径:
foo.xml
baz.xml
foobar.xml
这看起来很简单,但我找不到允许我搜索字符串中最后一个字符的DB2标量函数。我在监督什么吗?
我可以通过递归查询来做到这一点,但这对于这样一个简单的任务来说似乎有点过头了(哦,奇迹)非常慢:
WITH PATHFRAGMENTS (POS, PATHFRAGMENT) AS (
SELECT
1,
FILEPATH
FROM FOO
UNION ALL
SELECT
POSITION('/', PATHFRAGMENT, OCTETS) AS POS,
SUBSTR(PATHFRAGMENT, POSITION('/', PATHFRAGMENT, OCTETS)+1) AS PATHFRAGMENT
FROM PATHFRAGMENTS
)
SELECT DISTINCT PATHFRAGMENT FROM PATHFRAGMENTS WHERE POS = 0
答案 0 :(得分:8)
我认为您正在寻找的是LOCATE_IN_STRING()
scalar function。如果您使用负起始值,则信息中心必须说明这一点:
如果整数的值小于零,则搜索从 LENGTH(源字符串)+开始+ 1并继续每个位置 字符串的开头。
将其与LENGTH()
和RIGHT()
标量函数相结合,您就可以获得所需内容:
SELECT
RIGHT(
FILEPATH
,LENGTH(FILEPATH) - LOCATE_IN_STRING(FILEPATH,'/',-1)
)
FROM FOO
答案 1 :(得分:1)
实现此目的的一种方法是利用DB2 XQuery引擎的强大功能。以下对我有用(而且速度很快):
SELECT DISTINCT XMLCAST(
XMLQuery('tokenize($P, ''/'')[last()]' PASSING FILEPATH AS "P")
AS VARCHAR(512) )
FROM FOO
在这里,我使用tokenize将文件路径拆分为一系列标记,然后选择最后一个标记。其余的只是从SQL转换为XML类型再返回。
答案 2 :(得分:0)
您可以在一个声明中执行此操作:
select distinct reverse(substring(reverse(FILEPATH), 1, charindex('/', reverse(FILEPATH))-1))
from filetable
答案 3 :(得分:0)
我知道OP的问题已经解决但我决定发布以下信息,希望能帮助像我这样的人来到这里。
我在搜索我的类似问题的解决方案时遇到了这个问题,该解决方案具有完全相同的要求但是对于另一种也缺少REVERSE
函数的数据库。
在我的情况下,这是针对 OpenEdge(Progress)数据库,其语法略有不同。这使得INSTR
函数SELECT
SUBSTRING(
foo.filepath,
INSTR(foo.filepath, '/',1, LENGTH(foo.filepath) - LENGTH( REPLACE( foo.filepath, '/', '')))+1,
LENGTH(foo.filepath))
FROM foo
可以使用most Oracle typed databases offer。
所以我想出了以下代码:
SELECT
SUBSTRING(
foo.filepath,
INSTR(foo.filepath, '/',1, LENGTH( REPLACE( foo.filepath, '/', 'XX')) - LENGTH(foo.filepath))+1,
LENGTH(foo.filepath))
FROM foo
但是,对于我的特定情况(作为 OpenEdge(进度)数据库),这不会导致所需的行为,因为用空字符替换字符会给出与原始字符串相同的长度。这对我来说没有多大意义,但我能够通过以下代码绕过问题:
INSTR
现在我明白这段代码无法解决 T-SQL 的问题,因为除了提供Occurence
属性的 -- Drop the function if it already exists
IF OBJECT_ID('INSTR', 'FN') IS NOT NULL
DROP FUNCTION INSTR
GO
-- User-defined function to implement Oracle INSTR in SQL Server
CREATE FUNCTION INSTR (@str VARCHAR(8000), @substr VARCHAR(255), @start INT, @occurrence INT)
RETURNS INT
AS
BEGIN
DECLARE @found INT = @occurrence,
@pos INT = @start;
WHILE 1=1
BEGIN
-- Find the next occurrence
SET @pos = CHARINDEX(@substr, @str, @pos);
-- Nothing found
IF @pos IS NULL OR @pos = 0
RETURN @pos;
-- The required occurrence found
IF @found = 1
BREAK;
-- Prepare to find another one occurrence
SET @found = @found - 1;
SET @pos = @pos + 1;
END
RETURN @pos;
END
GO
函数之外别无选择。< / p>
为了彻底,我将添加创建此标量函数所需的代码,以便它可以像我在上面的示例中一样使用。
REVERSE
为避免显而易见,当SELECT
SUBSTRING(
foo.filepath,
LEN(foo.filepath) - CHARINDEX('\', REVERSE(foo.filepath))+2,
LEN(foo.filepath))
FROM foo
函数可用时,您不需要创建此标量函数,您只需得到所需的结果:
filter