從絕對位置提取不帶副檔名的文件名
我正在嘗試獲取包含在表的特定列的值中的文件名。我的表如下所示:
absolutel_path \\Path\filename.extension
我需要
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) );
填充:
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');
我原來的解決方案:
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;
給出結果:
my_file file1 file2 file3 file4 file5 file6 file -- << should be file7 file8 -- << should be file8.tar my_prog
閱讀@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
結果:
the_files file1 file2 file3 file4 file5 file6 file7 file8.tar my_prog
這也是正確答案!
當我在尋找解決方案時,我開始對正則表達式感興趣,因為它可以作為解決這個問題的一種手段。儘管我(我們)能夠/能夠使用“傳統” SQL 解決這個問題,但我很清楚正則表達式非常強大,即使 SQL 現在是圖靈完備的,但對於相對簡單的字元串操作問題,它可能會迅速變得非常複雜,所以我決定調查一下。
我找到了兩個正則表達式解決方案 - 公平地說,我不能聲稱自己已經這樣做了,這些解決方案是我在StackOverflow上提出的問題的結果。因此,正則表達式解決方案如下:
最好的是這個——
SELECT file_name, REGEXP_REPLACE(file_name, '^.*/([^/]*?)(\.[^/.]+)?$', '\1') AS filename FROM with_filename;
還有第二個,但恕我直言(以及原作者的)它有點像黑客 - 它涉及兩個嵌套
REGEXP_REPLACE
的 sSELECT file_name, REGEXP_REPLACE(REGEXP_REPLACE(file_name, '^.*/(.*)$', '\1'), '\.[^.]+$', '') AS filename FROM with_filename
最後,可能有一個解決方案可能同時使用 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;
結果是:
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
我嘗試了很多不同的排列,但無法讓它發揮作用。將不勝感激任何輸入!:-)
另一個有趣的函式是 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
結果:
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
同樣,這可能值得追求——沒有時間。
範例 DML/DDL
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');