达梦数据库中的一些巧妙的SQL
本文于 111 天前发布,最后更新于 91 天前

一、前言

本文可能不局限于 DM 数据库,用法是否可用需自行验证。

二、汇总

2.1 字段中是否包含中文

--查询NAME字段包含中文的
SELECT NAME FROM CS_ZW WHERE ASCIISTR(NAME) LIKE '%\%';
--查询NAME字段不包含中文的
SELECT NAME FROM CS_ZW WHERE ASCIISTR(NAME) NOT LIKE '%\%';

2.2 TIMESTAMP 类型取小时部分

SELECT DATE_FORMAT(SYSDATE(),'%H') AS HOUR FROM DUAL;

2.3 查询表的创建时间

SELECT NAME,CRTDATE AS "创建时间" FROM SYSOBJECTS WHERE "TYPE$" = 'SCHOBJ' AND "SUBTYPE$" = 'UTAB' AND NAME = '表名';

2.4 大字段类型查询时直接显示内容

创建测试表及数据

CREATE TABLE DZD (ID INT,B1 BLOB,C1 CLOB);
INSERT INTO TEST.DZD VALUES (1,'ABCDEF','MAKDJIDIJFIJDIJIENG');
INSERT INTO TEST.DZD VALUES (2,'BCDEF','NGJDJIEJIJFIJEWNAAS');
INSERT INTO TEST.DZD VALUES (3,'CDEF','JMEIGNABEIJGIIANAI');

方法一:【BLOB 类型不适用】

SELECT ID,C1::VARCHAR FROM TEST.DZD;

方法二:

--DBMS_LOB.SUBSTR(BLOB/CLOB/TEXT)
SELECT ID,DBMS_LOB.SUBSTR(B1),DBMS_LOB.SUBSTR(C1) FROM TEST.DZD;

方法三:

使用新工具 SQLark(百灵连接)

2.5 时间戳与日期类型的相互转化

日期类型转时间戳

SELECT UNIX_TIMESTAMP(SYSDATE);

时间戳转日期类型

SELECT FROM_UNIXTIME(1591644470);
SELECT FROM_UNIXTIME(1591644470,'YYYY-MM-DD');
SELECT FROM_UNIXTIME(1591644470,'YYYY-MM-DD HH24:MI:SS');

另 - 13 位时间戳转化方法

--截取后直接转化
SELECT FROM_UNIXTIME(SUBSTR(1709187648234,0,10)) FROM DUAL;
--TO_CHAR方式
SELECT TO_CHAR(1709187648234*1.0 / (1000*60*60*24) + TO_DATE('1970-01-01 08:00:00','YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD HH24:MI:SS');
SELECT TO_CHAR(1709187648234*1.0 / (1000*60*60*24) + TO_DATE('1970-01-01 08:00:00.000','YYYY-MM-DD HH24:MI:SS.MS'),'YYYY-MM-DD HH24:MI:SS.MS');

2.6 求一个或多个数中的最大值

创建测试表及数据

CREATE TABLE SCORE(ID INT PRIMARY KEY,NAME VARCHAR(30),YW INT,SX INT,YY INT);

使用 SQLark 的数据生成功能,生成成绩单数据。

--查询每名学生自己最好的一科成绩
SELECT GREATEST(YW,SX,YY),* FROM SCORE;

如图

2.7 计算一个字符串中某个字符的个数

示例:计算该字符串中 “F” 的个数。

SELECT LENGTH('ADSLFKJAKSJFDLJADSASF')-LENGTH(REPLACE('ADSLFKJAKSJFDLJADSASF', 'F' ,''));

思路:

思路:

  1. 将字符串中所找字符替换成”【就是将所找字符替换成空】
  2. 利用数学:字符串长度 - 字符串去掉所找字符后的长度 = 字符的个数

总结:

SELECT LENGTH('字符串')-LENGTH(REPLACE('字符串', '所找字符' ,''));

2.8 列转置(列转行)

创建测试表及数据

--创建表
CREATE TABLE LZH (ID INT, DT DATETIME (6), TEXT VARCHAR(8188));
--插入测试数据
INSERT INTO LZH (ID, DT, TEXT) VALUES (1, '2024-01-24 14:26:26.000000', 'a,B,c,d');
INSERT INTO LZH (ID, DT, TEXT) VALUES (5, '2024-01-24 14:26:26.000000', 'e,f,G');
INSERT INTO LZH (ID, DT, TEXT) VALUES (7, '2024-01-24 14:26:26.000000', 'h,i,J');

将 TEXT 字段以逗号分隔,拆分成新的一行数据

SELECT
A.*,
REGEXP_SUBSTR(A.TEXT, '[^,]{1,}', 1, B.L) AS SPLIT_FIELD
FROM
LZH A
JOIN (
SELECT
LEVEL AS L
FROM
DUAL
CONNECT BY LEVEL <= 100
) B ON REGEXP_COUNT (A.TEXT, ',') + 1 >= B.L
ORDER BY
3;

效果:

2.9 虚拟列

表中某字段由其他字段计算所得 - 计算列

CREATE TABLE SCORE_TEST (
YW CHAR(10),
SX CHAR(10),
YY CHAR(10),
ZF CHAR(10) AS (YW + SX + YY)
);
INSERT INTO SCORE_TEST(YW,SX,YY) VALUES ('92','73','84');
SELECT * FROM SCORE_TEST;

如图:

2.10 二进制转化为相应的 ASCII 码文本

SELECT UTL_RAW.CAST_TO_VARCHAR2(DBMS_LOB.SUBSTR(BLOB字段)) FROM TABLENAME;

2.11 分区表将手机号以最后一位数字分十个子表

思路:使用虚拟列进行范围分区

CREATE TABLE PHONEINFO (NAME VARCHAR(20),PHONE VARCHAR(20),PHONE_TAIL_NUMBER CHAR(1) AS (SUBSTR(PHONE,-1)))
PARTITION BY LIST(PHONE_TAIL_NUMBER) (
PARTITION P0 VALUES ('0'),
PARTITION P1 VALUES ('1'),
PARTITION P2 VALUES ('2'),
PARTITION P3 VALUES ('3'),
PARTITION P4 VALUES ('4'),
PARTITION P5 VALUES ('5'),
PARTITION P6 VALUES ('6'),
PARTITION P7 VALUES ('7'),
PARTITION P8 VALUES ('8'),
PARTITION P9 VALUES ('9')
);

2.12 CONCAT 函数拼接时间字段

CONCAT 函数拼接传参的字段时,时间字段不会带上单引号,可以在拼接字段时带上引号来解决

SELECT CONCAT('BETWEEN ',SYSDATE)--无单引号
UNION ALL
SELECT CONCAT('BETWEEN ',''''||SYSDATE||'''');--加单引号

2.13 自定义函数实现字段拼接【CURSOR】

创建测试数据

CREATE TABLE ZIDUANPINJIE (ID INT NOT NULL PRIMARY KEY, NAME VARCHAR(30));
INSERT INTO ZIDUANPINJIE VALUES (1,'武汉');
INSERT INTO ZIDUANPINJIE VALUES (2,'达梦');
INSERT INTO ZIDUANPINJIE VALUES (3,'数据库');
INSERT INTO ZIDUANPINJIE VALUES (4,'股份');
INSERT INTO ZIDUANPINJIE VALUES (5,'有限');
INSERT INTO ZIDUANPINJIE VALUES (6,'公司');
INSERT INTO ZIDUANPINJIE VALUES (7,'成功');
INSERT INTO ZIDUANPINJIE VALUES (8,'上市');
INSERT INTO ZIDUANPINJIE VALUES (9,'科创板');
COMMIT;

函数定义

CREATE OR REPLACE FUNCTION PINJIE_ALL_DATA_FROM_TABLE
RETURN VARCHAR IS
V_RESULT VARCHAR(100);
CURSOR TABLE_CURSOR IS
SELECT * FROM ZIDUANPINJIE;
BEGIN
FOR REC IN TABLE_CURSOR LOOP
V_RESULT := V_RESULT || REC.NAME;
--V_RESULT := V_RESULT ||'||' || REC.NAME; -- 添加分隔符
END LOOP;
RETURN V_RESULT;
END;
/

验证效果

SELECT "TEST"."PINJIE_ALL_DATA_FROM_TABLE"();

效果如图

2.14 IMAGA 字段转换为 VARCHAR 字段

创建测试表

CREATE TABLE IMG2VAR (ID INT PRIMARY KEY, PICTURE IMAGE);

使用 SQLark 的数据生成功能生成测试数据

转换

SELECT UTL_I18N.RAW_TO_CHAR(SUBSTRBLB(PICTURE,1,3000),'UTF8') FROM TEST.IMG2VAR;

效果图

2.15 LIKE 转义 ESCAPE

创建测试数据

CREATE TABLE TEST_LIKE (ID INT, NAME VARCHAR(200));
INSERT INTO TEST_LIKE VALUES(1,'FFFF');
INSERT INTO TEST_LIKE VALUES(2,'FF_FF');
INSERT INTO TEST_LIKE VALUES(3,'FF\FF');
INSERT INTO TEST_LIKE VALUES(4,'FF_A\A');
INSERT INTO TEST_LIKE VALUES(5,'FF_\FF');
INSERT INTO TEST_LIKE VALUES(6,'FF\_FF');
INSERT INTO TEST_LIKE VALUES(7,'FF%_%FF');
COMMIT;

一些查询示例:

(1)查询包含 “_” 的数据

SELECT * FROM TEST_LIKE WHERE NAME LIKE '%\_%' ESCAPE '\';
--或者
SELECT * FROM TEST_LIKE WHERE NAME LIKE '%A_%' ESCAPE 'A';

效果图:

(2)查询包含 “\_” 的数据

SELECT * FROM TEST_LIKE WHERE NAME LIKE '%\\\_%' ESCAPE '\';

效果图:

(3)查询包含 “%” 的数据

SELECT * FROM TEST_LIKE WHERE REGEXP_LIKE (NAME,'%');
--或者
SELECT * FROM TEST_LIKE WHERE NAME LIKE '%\%%' ESCAPE '\';

效果图:

2.16 字符串按分割符拆分成一列的多行

示例:将字符串 “AAA|BBB|CCC|DDD|EEE”,按 “|” 截取

方法一:SUBSTRING_INDEX 嵌套

SELECT SUBSTRING_INDEX('AAA|BBB|CCC|DDD|EEE','|',1) UNION ALL --AAA
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('AAA|BBB|CCC|DDD|EEE','|', 2),'|',-1) UNION ALL --BBB
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('AAA|BBB|CCC|DDD|EEE','|', 3),'|',-1) UNION ALL --CCC
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('AAA|BBB|CCC|DDD|EEE','|', 4),'|',-1) UNION ALL --DDD
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('AAA|BBB|CCC|DDD|EEE','|', 5),'|',-1); --EEE

方法二:REGEXP_SUBSTR 结合 LEVEL

SELECT
REGEXP_SUBSTR('AAA|BBB|CCC|DDD|EEE', '[^|]+', 1, LEVEL) AS SPLIT_VALUE
FROM
DUAL CONNECT BY
REGEXP_SUBSTR('AAA|BBB|CCC|DDD|EEE', '[^|]+', 1, LEVEL) IS NOT NULL;

方法三:

DECLARE
V_COUNT INT;
V_DATA VARCHAR(50);
V_SQL VARCHAR(5000);
BEGIN
SELECT LENGTH('AAA|BBB|CCC|DDD|EEE') - LENGTH(REPLACE('AAA|BBB|CCC|DDD|EEE', '|', '')) + 1 INTO V_COUNT FROM DUAL;
EXECUTE IMMEDIATE 'DROP TABLE IF EXISTS RESULT_TABLE;';
EXECUTE IMMEDIATE 'CREATE TABLE RESULT_TABLE (RES VARCHAR2(50));';
FOR I IN 1 .. V_COUNT LOOP
SET V_DATA = SUBSTRING_INDEX(SUBSTRING_INDEX('AAA|BBB|CCC|DDD|EEE', '|', I), '|', -1);
V_SQL = 'INSERT INTO RESULT_TABLE VALUES (:1);';
EXECUTE IMMEDIATE V_SQL USING V_DATA;
END LOOP;
END;

查询验证

SELECT * FROM RESULT_TABLE;

总结模板:

DECLARE
V_COUNT INT;
V_DATA VARCHAR(50);
V_SQL VARCHAR(5000);
BEGIN
SELECT LENGTH('字符串')-LENGTH(REPLACE('字符串', '分割符' ,''))+1 INTO V_COUNT FROM DUAL;
EXECUTE IMMEDIATE 'DROP TABLE IF EXISTS RESULT_TABLE;';
EXECUTE IMMEDIATE 'CREATE TABLE RESULT_TABLE (RES VARCHAR2(50));';
FOR I IN 1..V_COUNT LOOP
SET V_DATA = SUBSTRING_INDEX(SUBSTRING_INDEX('字符串','分割符', I),'分割符',-1);
V_SQL = 'INSERT INTO RESULT_TABLE VALUES (:1);';
EXECUTE IMMEDIATE V_SQL USING V_DATA;
END LOOP;
END;
--查询结果
SELECT * FROM RESULT_TABLE;

2.17 时间转化成秒数

SELECT TIME_TO_SEC('03:00:00') from dual;

效果:

三、后续

该文档不定时更新,如有发现新的 SQL,随时同步到该文章。

暂无评论

发送评论 编辑评论


|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇