我正在尝试获取包含在我的表的特定列的值中的文件名。我的桌子看起来像这样:
absolutel_path
\\Path\filename.extension
Run Code Online (Sandbox Code Playgroud)
我需要filename
从absolute_path
( \\Path\filename.extension
) 中提取文件名(在上面)。我应该使用哪个函数来获取我的文件名(子字符串)?
尽管我的第一个解决方案回答了问题,但我看到了 @DavidBoho 的回答,他提出了几个很好的观点。他建议如果文件名是,my_file.tar.gz
则返回值应该是,my_file.tar
并且如果文件根本没有扩展名,我的解决方案将失败。这里的所有代码都可以在这个fiddle 上找到。
给出表和数据如下:
CREATE TABLE with_filename
(
file_id INTEGER,
file_name VARCHAR (256)
);
Run Code Online (Sandbox Code Playgroud)
填充:
INSERT INTO with_filename
VALUES
(1, '/users/mcm1/ualaoip2/vmm/file1.pdf'),
(2, '/users/mcm1/ualaoip2/vmm/file2.py'),
(3, '/users/mcm1/ualaoip2/vmm/file3.pdf'),
(4, '/users/mcm1/ualaoip2/vmm/file4.c'),
(5, '/users/mcm1/ualaoip2/vmm/file5.java'),
(6, '/users/mcm1/ualaoip2/vmm/file6.class'),
(7, '/users/mcm1/ualaoip2/vmm/file7'),
(8, '/users/mcm1/ualaoip2/vmm/file8.tar.gz'),
(9, '/users/mcm1/my_prog.cpp');
Run Code Online (Sandbox Code Playgroud)
我原来的解决方案:
SELECT LEFT(
RIGHT(file_name, POSITION('/' IN REVERSE(file_name)) - 1),
POSITION('.' IN
RIGHT(file_name, POSITION('/' IN REVERSE(file_name)) - 1)) - 1
) AS my_file
FROM with_filename;
Run Code Online (Sandbox Code Playgroud)
给出结果:
my_file
file1
file2
file3
file4
file5
file6
file -- << should be file7
file8 -- << should be file8.tar
my_prog
Run Code Online (Sandbox Code Playgroud)
阅读@DavidBoho 的帖子后,他使用该SPLIT_PART
功能解决了文件 7 和 8 的问题 - 请参阅小提琴。我决定再看看我自己的 SQL,然后我想出了这个(也许更传统?):
SELECT
REPLACE(SUBSTRING(file_name, (LENGTH(file_name) + 2) - POSITION('/' IN REVERSE(file_name))),
RIGHT(file_name, POSITION('.' IN LEFT(REVERSE(file_name), POSITION('/' IN REVERSE(file_name)) - 1))),
'') AS the_files
FROM with_filename
Run Code Online (Sandbox Code Playgroud)
结果:
the_files
file1
file2
file3
file4
file5
file6
file7
file8.tar
my_prog
Run Code Online (Sandbox Code Playgroud)
这也是正确答案!
在我寻找解决方案的过程中,我对正则表达式作为解决此问题的一种方式产生了兴趣。尽管我(我们)能够使用“传统”SQL 解决这个问题,但我很清楚正则表达式非常强大,即使 SQL 现在是图灵完备的,但对于相对简单的字符串操作问题,它可能很快变得非常复杂,所以我决定调查一下。
我找到了两个正则表达式解决方案 - 公平地说,我不能声称自己已经这样做了,这些解决方案是我在StackOverflow 上提出的一个问题的结果。因此,正则表达式解决方案如下:
最好的就是这个——
SELECT
file_name,
REGEXP_REPLACE(file_name, '^.*/([^/]*?)(\.[^/.]+)?$', '\1') AS filename
FROM with_filename;
Run Code Online (Sandbox Code Playgroud)
还有第二个,但恕我直言(以及原作者的)它有点黑客 - 它涉及两个嵌套的REGEXP_REPLACE
s
SELECT
file_name,
REGEXP_REPLACE(REGEXP_REPLACE(file_name, '^.*/(.*)$', '\1'), '\.[^.]+$', '') AS filename
FROM with_filename
Run Code Online (Sandbox Code Playgroud)
最后,可能有一个解决方案可能一起使用 UNNEST 和 STRING_TO_ARRAY 函数 - 我想出了这个代码:
SELECT fn,
LEFT(fn, POSITION('.' IN fn) - 1) AS lef
FROM with_filename w,
UNNEST(STRING_TO_ARRAY(w.file_name, '/')) AS fn
GROUP BY fn
HAVING COUNT(fn) = 1
ORDER BY lef;
Run Code Online (Sandbox Code Playgroud)
这给出了结果:
fn lef
file7 file -- << should be file7
file1.pdf file1
file2.py file2
file3.pdf file3
file4.c file4
file5.java file5
file6.class file6
file8.tar.gz file8 -- << should be file8.tar
my_prog.cpp my_prog
Run Code Online (Sandbox Code Playgroud)
我为此尝试了许多不同的排列,但无法使其正常工作。将不胜感激任何输入!:-)
另一个有趣的函数是 REGEXP_SPLIT_TO_TABLE。
SELECT
fn,
COUNT(fn)
FROM
(
SELECT REGEXP_SPLIT_TO_TABLE(w.file_name, '/') AS fn
FROM with_filename w
) AS sq
GROUP BY fn
HAVING COUNT(fn) = 1
ORDER BY fn
Run Code Online (Sandbox Code Playgroud)
结果:
fn count
file1.pdf 1
file2.py 1
file3.pdf 1
file4.c 1
file5.java 1
file6.class 1
file7 1
file8.tar.gz 1
my_prog.cpp 1
Run Code Online (Sandbox Code Playgroud)
同样,这可能值得追求 - 没有时间。
CREATE TABLE with_filename
(
file_id INTEGER,
file_name VARCHAR (256)
);
INSERT INTO with_filename
VALUES
(1, '/users/mcm1/ualaoip2/vmm/file1.pdf'),
(2, '/users/mcm1/ualaoip2/vmm/file2.py'),
(3, '/users/mcm1/ualaoip2/vmm/file3.pdf'),
(4, '/users/mcm1/ualaoip2/vmm/file4.c'),
(5, '/users/mcm1/ualaoip2/vmm/file5.java'),
(6, '/users/mcm1/ualaoip2/vmm/file6.class'),
(7, '/users/mcm1/ualaoip2/vmm/file7'),
(8, '/users/mcm1/ualaoip2/vmm/file8.tar.gz'),
(9, '/users/mcm1/my_prog.cpp');
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
9244 次 |
最近记录: |