SQL 查询实例

字符串处理

数据准备:

create table n10(
  pos int4
);
insert into n10 (pos) values (1);
insert into n10 (pos) values (2);
-- ... 1 到 10
insert into n10 (pos) values (10);
--
create table table3(
  name text,
  address text
);
insert into table3 (line) values ('aladdin', 'china');
  • 串联字符串
-- Postgres / Oracle
select name || ' live in ' || address as msg from table3; -- aladdin live in china
-- MySQL / Postgres
select concat(name, ' live in ', address) as msg from table3; -- aladdin live in china
select concat_ws('_', name, address) from table8; -- aladdin_china
  • 查找匹配项
-- PostgreSQL / MySQL
select * from emp where emp_sal in (13000, 30000); -- 使用 in
-- 使用 like
select * from emp where emp_name like 'ala%'; -- 匹配单个字符使用 '_'
  • 遍历字符串
-- Postgres
select
       substring(t3.name, iter.pos, 1) as c
from
     table3 t3, n10 iter
where
      iter.pos <= length(t3.name);
-- a
-- l
-- a
-- d
-- d
-- i
-- n
  • 统计字符出现的次数
-- Postgres
select
       (length(name) - length(replace(name, 'a', ''))) as num
       -- 统计字符 a 出现的次数
from table3; -- 2
  • 删除不想要的字符
-- Postgres
select
       replace(translate(line, 'AEIOUaeiou', 'aaaaaaaaaa'), 'a', '')
       -- 将元音字符删除
from table3;
  • 分离字符串和数字
-- 准备工作
create table table1(
  line text
);
insert into table1 (line) values ('Jim1006');
-- Postgres
select
       replace(translate(line, '0123456789', '0000000000'), '0', '') as ename,
       cast(replace(translate(lower(line), 'asdfghjklzxcvbnmqwertyuiop', repeat('z', 26)), 'z', '') as integer) as year
from table1 t1;
  • 按字符串中的数字排序
-- Postgres
select line
from table1
order by cast(replace(translate(lower(line), 'asdfghjklzxcvbnmqwertyuiop', repeat('z', 26)), 'z', '') as integer);
  • 解析IP地址
create table table2(
  ip text
);
insert into table2 (ip) values ('144.132.11.3');
-- MySQL
select
       substring_index(substring_index(ip, '.', 1), '.', -1) as a,
       substring_index(substring_index(ip, '.', 2), '.', -1) as b,
       substring_index(substring_index(ip, '.', 3), '.', -1) as c,
       substring_index(substring_index(ip, '.', 4), '.', -1) as d
from table2;
-- PostgreSQL
select
       split_part(ip, '.', 1) as a,
       split_part(ip, '.', 2) as b,
       split_part(ip, '.', 3) as c,
       split_part(ip, '.', 4) as d
from table2;

数值处理

数据准备:

create table table3(
  id int4,
  score double precision
);
insert into table3 (id, score) values (1001, 97);
insert into table3 (id, score) values (1001, 95);
insert into table3 (id, score) values (1001, 98);
insert into table3 (id, score) values (1002, 93);
insert into table3 (id, score) values (1002, 99);
insert into table3 (id, score) values (1003, 94);
insert into table3 (id, score) values (1003, 99);
  • 计算均值
select avg(score) from table3;
-- 分组求均值
select id, round(avg(score)::numeric, 2) from table3 group by id;
select id, round(avg(coalesce(t3.score, 0))::numeric, 2) from table3 t3 group by id;
  • 去掉极值求均值
select
       avg(score)
from
     table3
where
      score not in (
                    (select max(score) from table3),
                    (select min(score) from table3)
                   );
  • 最大值与最小值
select min(score) as min, max(score) as max from table3;
-- 分组求最大值与最小值
select id, min(score) as min, max(score) as max from table3 group by id;
select id, min(coalesce(score, 0)) as min, max(coalesce(score, 0)) as max from table3 group by id;
  • 求和
select sum(score) as sum from table3;
-- 分组求和
select id, sum(score) as sum from table3 group by id;
select id, sum(coalesce(score, 0)) from table3 group by id;
  • 计算行数
-- count(*) 统计行数,无论非 null 否
select count(*) as count from table3;
-- 计算某列值个数
select count(score) as count -- 如果 score 为 null 则不计数
from table3;
-- 分组求行数
select id, count(*) as count from table3 group by id;
  • 求众数
select score
from
     (
       select
              score, (dense_rank() over (order by e.count desc)) as rnk
       from
            (
              select score, count(score) as count
              from table3
              group by score
            ) as e
     ) as t
where t.rnk = 1;
  • 计算百分比
-- 计算 id 为 1001 学生分数占全部分数的百分比
select (sum(case when id = 1001 then score end) / sum(score)) * 100 as pct from table3;

日期处理

  • 提取年月日
-- Postgres
select extract(year from now()) as year;
-- mon: 月
-- day: 日
-- week: 一年中第几周
-- doy: 一年中第几天

对 NULL 值处理

  • 查找 NULL 值
-- PostgreSQL / MySQL
select * from emp where emp_name is null;
  • 将 NULL 值转换为实际值
-- PostgreSQL / MySQL
select coalesce(emp_name, 'Secret Superstar') as name from emp;
  • 比较中有 NULL 值
-- 数据准备
create table table2(
  name text,
  sal double precision
);
create table table3(
  name text,
  sal double precision
);
insert into table2 (name, sal) values ('aladdin', 12000), ('bilib', null);
insert into table3 (name, sal) values ('chrome', 3000);
-- 使用 coalesce 函数进行 null 值的转换
select * from table2 t2
where coalesce(t2.sal, 0) > (select t3.sal from table3 t3 where t3.name = 'chrome');

CASE...WHEN

  • PostgerSQL / MySQL /Oracle
select
     emp_name,
     emp_sal,
     case
       when emp_sal < 10000.0 then 'low'
       when emp_sal >= 10000.0 and emp_sal < 20000.0 then 'mid'
       when emp_sal >= 20000.0 and emp_sal < 50000.0 then 'high'
       else 'very high'
     end as "status"
from emp;

返回指定行数

  • PostgreSQL / MySQL
-- 返回指定行数,PostgreSQL 和 MySQL 一样
select * from emp order by emp_sal limit 3;
-- 随机返回 N 行,Postgre 实现
select * from emp order by random() limit 3;
-- 随机返回 N 行,MySQL 实现
select * from emp order by rand() limit 3;
  • Oracle
select * from emp where rownum <= 3;

排序

  • 基本排序
-- PostgreSQL / MySQL
-- 单字段
select * from emp order by emp_sal desc; -- 将序,默认升序 / asc
-- 多字段
select * from emp order by emp_sal desc, emp_name;
-- 子字段
select * from emp order by substr(emp_name, length(emp_name) - 2);
  • 对字段中的数字 / 字母排序
-- 数据处理
create table public.table2(
msg text
);
insert into public.table2 values ('aladdin 800'), ('bilib 300'), ('chrom 600');

-- 下面连个方法对 MySQL 不适用
-- 对字段中的数字排序
select
     *
from
   public.table2
order by
       replace(msg, replace(translate(msg, '0123456789', '#########'), '#', ''), '');
-- 对字段中的字母进行排序
select
     *
from public.table2
order by
       replace(translate(msg, '0123456789', '#########'), '#', '');
  • 对 NULL 进行更高级的排序
-- 数据准备
create table table4(
name text,
sal double precision
);
insert into
public.table4(name, sal)
values 
       ('alad', 0),
       ('bilib', 500),
       ('chrome', 1000),
       ('dell', null),
       ('echo', null);


-- 最基本的排序
select * from public.table4 order by sal desc; -- 这样 null 值就会到最上面
-- 让 null 值下来
with temp as(
select name,
       sal,
       case
         when sal is null
           then 0 else 1
         end as is_null
from public.table4
)
select name, sal from temp order by is_null desc, sal desc; -- 其它解决方案类似
  • 根据条件排序
select * from table4
order by
       case 
         when name = 'alad'
           then sal
         else name
       end desc;

集合操作

  • 合并
    UNION 会去重复项,UNION ALL 不会,如果不是特殊要求,一般都使用 UNION ALL,UNION 相当于在 UNION ALL 的基础上做一次 distinct 操作:
select name, sal from table5
union all
select name, sal from public.table6;
  • 交集与差集
-- 数据准备
create table public.table1(
name text,
hobby text
);
insert into
public.table1 (name, hobby)
values
       ('aladdin', 'Ping pong'),
       ('aladdin', 'Computer games'),
       ('bilil', 'Basketball'),
       ('bilib', 'Computer games');

-- Postgres
-- intersect 求交集
select
     hobby
from
   table1
where
    name = 'aladdin'
intersect
select
     hobby
from
   table1
where name = 'bilib'; -- Computer games

-- 使用基础语句实现
select
     t1.hobby
from table1 t1
inner join table1 t2 
  on
    t1.name = 'aladdin' and
    t2.name = 'bilib' and
    t1.hobby = t2.hobby;

-- (A - B) 求差集,Oracle 使用 minus 关键字实现
select
     hobby
from
   table1
where
    name = 'aladdin'
except
select
     hobby
from table1
where
    name = 'bilib'; -- Ping pong

-- 使用子查询实现
select
     t1.hobby
from
   table1 t1
where
    t1.name = 'aladdin' and t1.hobby not in (select t2.hobby from table1 t2 where t2.name = 'bilib');
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容