从绝对位置提取没有扩展名的文件名

Tyl*_*den 4 substring

我正在尝试获取包含在我的表的特定列的值中的文件名。我的桌子看起来像这样:

absolutel_path
\\Path\filename.extension
Run Code Online (Sandbox Code Playgroud)

我需要filenameabsolute_path( \\Path\filename.extension) 中提取文件名(在上面)。我应该使用哪个函数来获取我的文件名(子字符串)?

Vér*_*ace 8

编辑:

尽管我的第一个解决方案回答了问题,但我看到了 @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_REPLACEs

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)

同样,这可能值得追求 - 没有时间。

示例 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');
Run Code Online (Sandbox Code Playgroud)