使用 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 列中的文件的可读“文件大小”的优雅方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
如何调用具有 IN/OUT 参数并通过 DB Link 返回 BLOB 的 Oracle PL/SQL 函数
石英 2.2.1+jboss EAP 6.4 ClassNotFoundException oracle.sql.BLOB