• 一个很少见但很有用的SQL功能


    我最近偶然发现了一个标准的SQL特性,令我惊讶的是,这个特性在HSQLDB中实现了。这个关键字是CORRESPONDING ,它可以和所有的集合操作一起使用,包括UNIONINTERSECT 、和EXCEPT

    让我们来看看sakila数据库。它有3个表,里面都是人:

    1. CREATE TABLE actor (
    2. actor_id integer NOT NULL PRIMARY KEY,
    3. first_name varchar(45) NOT NULL,
    4. last_name varchar(45) NOT NULL,
    5. last_update timestamp
    6. );
    7. CREATE TABLE customer (
    8. customer_id integer NOT NULL PRIMARY KEY,
    9. store_id smallint NOT NULL,
    10. first_name varchar(45) NOT NULL,
    11. last_name varchar(45) NOT NULL,
    12. email varchar(50),
    13. address_id smallint NOT NULL,
    14. create_date date NOT NULL,
    15. last_update timestamp,
    16. active boolean
    17. );
    18. CREATE TABLE staff (
    19. staff_id integer NOT NULL PRIMARY KEY,
    20. first_name varchar(45) NOT NULL,
    21. last_name varchar(45) NOT NULL,
    22. address_id smallint NOT NULL,
    23. email varchar(50),
    24. store_id smallint NOT NULL,
    25. active boolean NOT NULL,
    26. username varchar(16) NOT NULL,
    27. password varchar(40),
    28. last_update timestamp,
    29. picture blob
    30. );
    31. 复制代码

    相似,但不相同。如果我们想从我们的数据库中获得所有的 "人 "呢?在任何普通的数据库产品中,有一种方法可以做到这一点:

    1. SELECT first_name, last_name
    2. FROM actor
    3. UNION ALL
    4. SELECT first_name, last_name
    5. FROM customer
    6. UNION ALL
    7. SELECT first_name, last_name
    8. FROM staff
    9. ORDER BY first_name, last_name
    10. 复制代码

    结果可能看起来像这样:

    1. |first_name|last_name|
    2. |----------|---------|
    3. |AARON |SELBY |
    4. |ADAM |GOOCH |
    5. |ADAM |GRANT |
    6. |ADAM |HOPPER |
    7. |ADRIAN |CLARY |
    8. |AGNES |BISHOP |
    9. |AL |GARLAND |
    10. |ALAN |DREYFUSS |
    11. |... |... |
    12. 复制代码

    使用CORRESPONDING

    现在,在HSQLDB中,以及在标准SQL中,你可以使用CORRESPONDING 来完成这种任务。比如说:

    1. SELECT *
    2. FROM actor
    3. UNION ALL CORRESPONDING
    4. SELECT *
    5. FROM customer
    6. UNION ALL CORRESPONDING
    7. SELECT *
    8. FROM staff
    9. ORDER BY first_name, last_name
    10. 复制代码

    其结果是这样的:

    1. |first_name|last_name|last_update |
    2. |----------|---------|-----------------------|
    3. |AARON |SELBY |2006-02-15 04:57:20.000|
    4. |ADAM |GOOCH |2006-02-15 04:57:20.000|
    5. |ADAM |GRANT |2006-02-15 04:34:33.000|
    6. |ADAM |HOPPER |2006-02-15 04:34:33.000|
    7. |ADRIAN |CLARY |2006-02-15 04:57:20.000|
    8. |AGNES |BISHOP |2006-02-15 04:57:20.000|
    9. |AL |GARLAND |2006-02-15 04:34:33.000|
    10. |ALAN |DREYFUSS |2006-02-15 04:34:33.000|
    11. |... |... |... |
    12. 复制代码

    那么,发生了什么?列FIRST_NAME,LAST_NAME, 和LAST_UPDATE 是这三个表所共有的。换句话说,如果你针对HSQLDB中的INFORMATION_SCHEMA ,运行这个查询:

    1. SELECT column_name
    2. FROM information_schema.columns
    3. WHERE table_name = 'ACTOR'
    4. INTERSECT
    5. SELECT column_name
    6. FROM information_schema.columns
    7. WHERE table_name = 'CUSTOMER'
    8. INTERSECT
    9. SELECT column_name
    10. FROM information_schema.columns
    11. WHERE table_name = 'STAFF'
    12. 复制代码

    你得到的正是这3个列:

    1. |COLUMN_NAME|
    2. |-----------|
    3. |FIRST_NAME |
    4. |LAST_NAME |
    5. |LAST_UPDATE|
    6. 复制代码

    换句话说,CORRESPONDING ,在集合操作的子查询中创建列的交集(即 "共享列"),投影这些,并应用该投影的集合操作。在某种程度上,这类似于一个 [NATURAL JOIN](https://blog.jooq.org/impress-your-coworkers-with-a-sql-natural-full-outer-join/),后者也试图找到列的交集以产生一个连接谓词。然而,NATURAL JOIN ,然后投影所有的列(或列的联合),而不仅仅是共享的列。

    使用CORRESPONDING BY

    就像NATURAL JOIN ,这是个有风险的操作。只要一个子查询改变了它的投影(例如,由于表的列重命名),所有这些查询的结果也会改变,甚至可能不会产生语法错误,只是结果不同。

    事实上,在上面的例子中,我们可能根本不关心那个LAST_UPDATE 列。它被意外地包含在UNION ALL 的集合操作中,就像NATURAL JOIN 会意外地使用LAST_UPDATE 来连接一样。

    对于连接,我们可以使用JOIN .. USING (first_name, last_name) ,至少指定我们想通过哪一个共享列名来连接这两个表。使用CORRESPONDING ,我们可以为同样的目的提供可选的BY 子句:

    1. SELECT *
    2. FROM actor
    3. UNION ALL CORRESPONDING BY (first_name, last_name)
    4. SELECT *
    5. FROM customer
    6. UNION ALL CORRESPONDING BY (first_name, last_name)
    7. SELECT *
    8. FROM staff
    9. ORDER BY first_name, last_name;
    10. 复制代码

    现在,这只产生了两个想要的列:

    1. |first_name|last_name|
    2. |----------|---------|
    3. |AARON |SELBY |
    4. |ADAM |GOOCH |
    5. |ADAM |GRANT |
    6. |ADAM |HOPPER |
    7. |ADRIAN |CLARY |
    8. |AGNES |BISHOP |
    9. |AL |GARLAND |
    10. |ALAN |DREYFUSS |
    11. |... |... |
    12. 复制代码

    事实上,这样一来,我们甚至可以有意义地使用INTERSECT和EXCEPT的语法,例如,找到与某个演员共享名字的客户:

    1. SELECT *
    2. FROM actor
    3. INTERSECT CORRESPONDING BY (first_name, last_name)
    4. SELECT *
    5. FROM customer
    6. ORDER BY first_name, last_name;
    7. 复制代码

    制作:

    1. |first_name|last_name|
    2. |----------|---------|
    3. |JENNIFER |DAVIS |
    4. 复制代码

    其他方言

    我以前没有在其他方言中多次遇到过这种语法。也许,它在将来会运到PostgreSQL中。Vik Fearing已经在做一个分支了:

    小伙伴们有兴趣想了解内容和更多相关学习资料的请点赞收藏+评论转发+关注我,后面会有很多干货。
    我有一些面试题、架构、设计类资料可以说是程序员面试必备!所有资料都整理到网盘了,需要的话欢迎下载!私信我回复【07】即可免费获取

     


    链接:https://juejin.cn/post/7126351838349099022
     

  • 相关阅读:
    正则表达式语法解析
    Golang | Leetcode Golang题解之第147题对链表进行插入排序
    Go语言操作protobuf协议使用详解
    jsonschema脚本测试
    面试突击24:为什么wait和notify必须放在synchronized中?
    MySQL—— 用户创建和权限管理
    【docker desktop】创建node:18 server
    仿`gRPC`功能实现像调用本地方法一样调用其他服务器方法
    C++知识点总结(6):高精度乘法
    CSS中如何在table中隐藏表格中从第4个开始的多个 <tr> 元素
  • 原文地址:https://blog.csdn.net/wadfdhsajd/article/details/126128889