使用 SQL 返回存储在 oracle blob 列中的文件的可读“文件大小”的优雅方法是啥?

Posted

技术标签:

【中文标题】使用 SQL 返回存储在 oracle blob 列中的文件的可读“文件大小”的优雅方法是啥?【英文标题】:What is an elegant way to return a readable 'file size' of a file stored in an oracle blob column using SQL?使用 SQL 返回存储在 oracle blob 列中的文件的可读“文件大小”的优雅方法是什么? 【发布时间】:2009-05-08 17:34:39 【问题描述】:

您将如何编写 SQL 查询以更易于阅读的形式获取 blob 的大小?该示例类似于将大型 word 文档存储在表上的 blob 中。我想执行类似的操作:

select fnc_getReadableSize(documents.doc) from documents where id = ?

输出: 23.4 MB

【问题讨论】:

【参考方案1】:

“可读”部分是我应该更多强调的。这是我现在整理的内容。

WITH file_sizes AS
     (SELECT 1048576 MEGABYTE, 1024 KILOBYTE,
             DBMS_LOB.GETLENGTH (BLOB_COLUMN) byte_size
        FROM BLOB_COLUMN)
SELECT (CASE TRUNC (byte_size / MEGABYTE)
           WHEN 0
              THEN TO_CHAR ((byte_size / KILOBYTE), '999,999') || ' KB'
           ELSE TO_CHAR ((byte_size / MEGABYTE), '999,999.00') || ' MB'
        END
       ) display_size
  FROM file_sizes


Output:

DISPLAY_SIZE  
--------------
       1.88 MB
     433 KB   
     540 KB   
     333 KB   
       1.57 MB
       1.17 MB

【讨论】:

WHEN byte_size < MEGABYTE THEN 不是更容易/更容易阅读吗?【参考方案2】:
SELECT DBMS_LOB.GETLENGTH(COLUMN_NAME) FROM DOCUMENTS

【讨论】:

我应该强调“可读”部分。我最终使用 WITH 子句来建立我的常量,然后任意决定 KB 和 MB 变化足以满足我的即时报告需求。 作为额外但未被 OP 要求的,它也可以与 BFILE 一起使用:select dbms_lob.getlength(bfilename('MYDIR', 'oracle.png')) s from dual;【参考方案3】:

这是格式化问题的纯 SQL 解决方案。它使用以 1024 为底的对数来获取数字的长度。

WITH my_values AS (
   SELECT                              4 AS my_value FROM DUAL UNION ALL
   SELECT                             42 AS my_value FROM DUAL UNION ALL
   SELECT                            424 AS my_value FROM DUAL UNION ALL
   SELECT                           4242 AS my_value FROM DUAL UNION ALL
   SELECT                          42424 AS my_value FROM DUAL UNION ALL
   SELECT                         424242 AS my_value FROM DUAL UNION ALL
   SELECT                        4242424 AS my_value FROM DUAL UNION ALL
   SELECT                       42424242 AS my_value FROM DUAL UNION ALL
   SELECT                      424242424 AS my_value FROM DUAL UNION ALL
   SELECT                     4242424242 AS my_value FROM DUAL UNION ALL
   SELECT                    42424242424 AS my_value FROM DUAL UNION ALL
   SELECT                   424242424242 AS my_value FROM DUAL UNION ALL
   SELECT                  4242424242424 AS my_value FROM DUAL UNION ALL
   SELECT                 42424242424242 AS my_value FROM DUAL UNION ALL
   SELECT                424242424242424 AS my_value FROM DUAL UNION ALL
   SELECT               4242424242424242 AS my_value FROM DUAL UNION ALL
   SELECT              42424242424242424 AS my_value FROM DUAL UNION ALL
   SELECT             424242424242424242 AS my_value FROM DUAL UNION ALL
   SELECT            4242424242424242424 AS my_value FROM DUAL UNION ALL
   SELECT           42424242424242424242 AS my_value FROM DUAL UNION ALL
   SELECT          424242424242424242424 AS my_value FROM DUAL UNION ALL
   SELECT         4242424242424242424242 AS my_value FROM DUAL UNION ALL
   SELECT        42424242424242424242424 AS my_value FROM DUAL UNION ALL
   SELECT       424242424242424242424242 AS my_value FROM DUAL UNION ALL
   SELECT      4242424242424242424242424 AS my_value FROM DUAL UNION ALL
   SELECT     42424242424242424242424242 AS my_value FROM DUAL UNION ALL
   SELECT    424242424242424242424242424 AS my_value FROM DUAL UNION ALL
   SELECT   4242424242424242424242424242 AS my_value FROM DUAL
),
exponents AS (
   SELECT my_value,
          TRUNC((LN(my_value) / LN(1024))) AS exponent
     FROM my_values
),
base_values AS (
  SELECT my_value,
         exponent,
         ROUND(my_value / POWER(1024, exponent), 3) AS base_value
    FROM exponents
),
prefixes AS (
   SELECT 0 AS exponent,    'B' AS unit FROM DUAL UNION ALL
   SELECT 1 AS exponent,  'KiB' AS unit FROM DUAL UNION ALL
   SELECT 2 AS exponent,  'MiB' AS unit FROM DUAL UNION ALL
   SELECT 3 AS exponent,  'GiB' AS unit FROM DUAL UNION ALL
   SELECT 4 AS exponent,  'TiB' AS unit FROM DUAL UNION ALL
   SELECT 5 AS exponent,  'PiB' AS unit FROM DUAL UNION ALL
   SELECT 6 AS exponent,  'EiB' AS unit FROM DUAL UNION ALL
   SELECT 7 AS exponent,  'ZiB' AS unit FROM DUAL UNION ALL
   SELECT 8 AS exponent,  'YiB' AS unit FROM DUAL),
formatted AS (
   SELECT b.my_value,
          b.exponent,
          b.base_value,
          TO_CHAR(b.base_value, '999.000') || ' ' || p.unit AS engineering_notation
     FROM base_values b
     JOIN prefixes p
       ON p.exponent = b.exponent)
SELECT * FROM formatted;



  MY_VALUE   EXPONENT BASE_VALUE ENGINEERING_NOTATION
---------- ---------- ---------- ------------------------------------------------
         4          0          4    4.000 B
        42          0         42   42.000 B
       424          0        424  424.000 B
      4242          1      4.143    4.143 KiB
     42424          1      41.43   41.430 KiB
    424242          1    414.299  414.299 KiB
   4242424          2      4.046    4.046 MiB
  42424242          2     40.459   40.459 MiB
 424242424          2    404.589  404.589 MiB
4242424242          3      3.951    3.951 GiB
4.2424E+10          3     39.511   39.511 GiB
4.2424E+11          3    395.107  395.107 GiB
4.2424E+12          4      3.858    3.858 TiB
4.2424E+13          4     38.585   38.585 TiB
4.2424E+14          4    385.846  385.846 TiB
4.2424E+15          5      3.768    3.768 PiB
4.2424E+16          5      37.68   37.680 PiB
4.2424E+17          5    376.803  376.803 PiB
4.2424E+18          6       3.68    3.680 EiB
4.2424E+19          6     36.797   36.797 EiB
4.2424E+20          6    367.972  367.972 EiB
4.2424E+21          7      3.593    3.593 ZiB
4.2424E+22          7     35.935   35.935 ZiB
4.2424E+23          7    359.347  359.347 ZiB
4.2424E+24          8      3.509    3.509 YiB
4.2424E+25          8     35.093   35.093 YiB
4.2424E+26          8    350.925  350.925 YiB

这是 PL/SQL 中类似的解决方案

SET SERVEROUTPUT ON
DECLARE
   FUNCTION get_human_readable_byte_size(
      byte_size_ IN NUMBER) RETURN VARCHAR2;

   FUNCTION get_human_readable_byte_size(
      byte_size_ IN NUMBER) RETURN VARCHAR2
   IS
      exponent_   NUMBER;
      base_value_ NUMBER;
      unit_       VARCHAR2(255);
      formatted_  VARCHAR2(255);
   BEGIN
      exponent_ := TRUNC((LN(byte_size_) / LN(1024)));
      base_value_ := ROUND(byte_size_ / POWER(1024, exponent_), 3);
      SELECT DECODE(exponent_,
                    0, 'B',
                    1, 'KiB',
                    2, 'MiB',
                    3, 'GiB',
                    4, 'TiB',
                    5, 'PiB',
                    6, 'EiB',
                    7, 'ZiB',
                    8, 'YiB',
                    '* 1024 ^ ' || exponent_) INTO unit_ 
        FROM DUAL;
      formatted_ := TO_CHAR(base_value_, '999.000') || ' ' || unit_;
      RETURN formatted_;
   END get_human_readable_byte_size;
BEGIN
   dbms_output.put_line(get_human_readable_byte_size(4));
   dbms_output.put_line(get_human_readable_byte_size(42));
   dbms_output.put_line(get_human_readable_byte_size(424));
   dbms_output.put_line(get_human_readable_byte_size(4242));
   dbms_output.put_line(get_human_readable_byte_size(42424));
   dbms_output.put_line(get_human_readable_byte_size(424242));
   dbms_output.put_line(get_human_readable_byte_size(4242424));
   dbms_output.put_line(get_human_readable_byte_size(42424242));
   dbms_output.put_line(get_human_readable_byte_size(424242424));
   dbms_output.put_line(get_human_readable_byte_size(4242424242));
   dbms_output.put_line(get_human_readable_byte_size(42424242424));
   dbms_output.put_line(get_human_readable_byte_size(424242424242));
   dbms_output.put_line(get_human_readable_byte_size(4242424242424));
   dbms_output.put_line(get_human_readable_byte_size(42424242424242));
   dbms_output.put_line(get_human_readable_byte_size(424242424242424));
   dbms_output.put_line(get_human_readable_byte_size(4242424242424242));
   dbms_output.put_line(get_human_readable_byte_size(42424242424242424));
   dbms_output.put_line(get_human_readable_byte_size(424242424242424242));
   dbms_output.put_line(get_human_readable_byte_size(4242424242424242424));
   dbms_output.put_line(get_human_readable_byte_size(42424242424242424242));
   dbms_output.put_line(get_human_readable_byte_size(424242424242424242424));
   dbms_output.put_line(get_human_readable_byte_size(4242424242424242424242));
   dbms_output.put_line(get_human_readable_byte_size(42424242424242424242424));
   dbms_output.put_line(get_human_readable_byte_size(424242424242424242424242));
   dbms_output.put_line(get_human_readable_byte_size(4242424242424242424242424));
   dbms_output.put_line(get_human_readable_byte_size(42424242424242424242424242));
   dbms_output.put_line(get_human_readable_byte_size(424242424242424242424242424));
   dbms_output.put_line(get_human_readable_byte_size(4242424242424242424242424242));
   dbms_output.put_line(get_human_readable_byte_size(42424242424242424242424242424));
   dbms_output.put_line(get_human_readable_byte_size(424242424242424242424242424242));
   dbms_output.put_line(get_human_readable_byte_size(4242424242424242424242424242424));
END;
/


4.000 B
42.000 B
424.000 B
4.143 KiB
41.430 KiB
414.299 KiB
4.046 MiB
40.459 MiB
404.589 MiB
3.951 GiB
39.511 GiB
395.107 GiB
3.858 TiB
38.585 TiB
385.846 TiB
3.768 PiB
37.680 PiB
376.803 PiB
3.680 EiB
36.797 EiB
367.972 EiB
3.593 ZiB
35.935 ZiB
359.347 ZiB
3.509 YiB
35.093 YiB
350.925 YiB
3.427 * 1024 ^ 9
34.270 * 1024 ^ 9
342.700 * 1024 ^ 9
3.347 * 1024 ^ 10

【讨论】:

以上是关于使用 SQL 返回存储在 oracle blob 列中的文件的可读“文件大小”的优雅方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

ORACLE数据库BLOB如何转化类型

Oracle Blob - 存储大小还是计算?

ORACLE SQL中获取BLOB的图像格式

如何调用具有 IN/OUT 参数并通过 DB Link 返回 BLOB 的 Oracle PL/SQL 函数

石英 2.2.1+jboss EAP 6.4 ClassNotFoundException oracle.sql.BLOB

ODAC 组件支持 Oracle 8 的 BLOB 和 CLOB 数据类型