zoukankan      html  css  js  c++  java
  • PostgreSQL之查询

    表连接

    表t1:

     num | name
    -----+------
       1 | a
       2 | b
       3 | c

    表t2:

     num | value
    -----+-------
       1 | xxx
       3 | yyy
       5 | zzz

    1.交叉连接

    T1 CROSS JOIN T2

      对来自于T1T2的行的每一种可能的组合(即笛卡尔积),连接表将包含这样一行:它由所有T1里面的列后面跟着所有T2里面的列构成。如果两个表分别有 N 和 M 行,连接表将有 N * M 行。

      FROM T1 CROSS JOIN T2等效于FROM T1 INNER JOIN T2 ON TRUE(见下文)。它也等效于FROM T1,T2

    => SELECT * FROM t1 CROSS JOIN t2;
     num | name | num | value
    -----+------+-----+-------
       1 | a    |   1 | xxx
       1 | a    |   3 | yyy
       1 | a    |   5 | zzz
       2 | b    |   1 | xxx
       2 | b    |   3 | yyy
       2 | b    |   5 | zzz
       3 | c    |   1 | xxx
       3 | c    |   3 | yyy
       3 | c    |   5 | zzz
    (9 rows)

    2.条件连接

    T1 { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2 ON boolean_expression
    T1 { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2 USING ( join column list )
    T1 NATURAL { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2

      INNEROUTER对所有连接形式都是可选的。INNER是缺省;LEFTRIGHTFULL指示一个外连接。连接条件ONUSING子句中指定, 或者用关键字NATURAL隐含地指定。连接条件决定来自两个源表中的哪些行是匹配”的。  

      2.1 INNER JOIN

      对于 T1 的每一行 R1,生成的连接表都有一行对应 T2 中的每一个满足和 R1 的连接条件的行。

    => SELECT * FROM t1 INNER JOIN t2 ON t1.num = t2.num;
     num | name | num | value
    -----+------+-----+-------
       1 | a    |   1 | xxx
       3 | c    |   3 | yyy

      2.2  LEFT OUTER JOIN

      列用空值补齐。因此,生成的连接表里为来自 T1 的每一行都至少包含一行。首先,执行一次内连接。然后,为 T1 中每一个无法在连接条件上匹配 T2 里任何一行的行返回一个连接行,该连接行中 T2 的列用空值补齐。因此,生成的连接表里为来自 T1 的每一行都至少包含一行。

    => SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num;
     num | name | num | value
    -----+------+-----+-------
       1 | a    |   1 | xxx
       2 | b    |     |
       3 | c    |   3 | yyy

      2.3  RIGHT OUTER JOIN

      首先,执行一次内连接。然后,为 T2 中每一个无法在连接条件上匹配 T1 里任何一行的行返回一个连接行,该连接行中 T1 的列用空值补齐。因此,生成的连接表里为来自 T2 的每一行都至少包含一行。

    => SELECT * FROM t1 RIGHT JOIN t2 ON t1.num = t2.num;
     num | name | num | value
    -----+------+-----+-------
       1 | a    |   1 | xxx
       3 | c    |   3 | yyy
         |      |   5 | zzz
    (3 rows)

      2.4 FULL OUTER JOIN

      首先,执行一次内连接。然后,为 T1 中每一个无法在连接条件上匹配 T2 里任何一行的行返回一个连接行,该连接行中 T2 的列用空值补齐。同样,为 T2 中每一个无法在连接条件上匹配 T1 里任何一行的行返回一个连接行,该连接行中 T1 的列用空值补齐。

    => SELECT * FROM t1 FULL JOIN t2 ON t1.num = t2.num;
     num | name | num | value
    -----+------+-----+-------
       1 | a    |   1 | xxx
       2 | b    |     |
       3 | c    |   3 | yyy
         |      |   5 | zzz

     

    VALUES列表

      VALUES提供了一种生成常量表”的方法,它可以被使用在一个查询中而不需要实际在磁盘上创建一个表。

    VALUES ( expression [, ...] ) [, ...]
    => SELECT * FROM (VALUES (1, 'one'), (2, 'two'), (3, 'three')) AS t (num,letter);
     num | letter
    -----+--------
       1 | one
       2 | two
       3 | three
    (3 rows)

    从修改的行中返回数据

      在INSERT中,可用于RETURNING的数据是插入的行。 

    CREATE TABLE users (firstname text, lastname text, id serial primary key);
    
    INSERT INTO users (firstname, lastname) VALUES ('Joe', 'Cool') RETURNING id;

      在UPDATE中,可用于RETURNING的数据是被修改行的新内容。

    UPDATE products SET price = price * 1.10
      WHERE price <= 99.99
      RETURNING name, price AS new_price;

      在DELETE中,可用于RETURNING的数据是删除行的内容。

    DELETE FROM products
      WHERE obsoletion_date = 'today'
      RETURNING *;

    WITH查询

      WITH提供了一种方式来书写在一个大型查询中使用的辅助语句。这些语句通常被称为公共表表达式或CTE,它们可以被看成是定义只在一个查询中存在的临时表。在WITH子句中的每一个辅助语句可以是一个SELECTINSERTUPDATEDELETE,并且WITH子句本身也可以被附加到一个主语句,主语句也可以是SELECTINSERTUPDATEDELETE

      1. WITH中的SELECT

      WITHSELECT的基本价值是将复杂的查询分解称为简单的部分。

    WITH regional_sales AS (
        SELECT region, SUM(amount) AS total_sales
        FROM orders
        GROUP BY region
    ), top_regions AS (
        SELECT region
        FROM regional_sales
        WHERE total_sales > (SELECT SUM(total_sales)/10 FROM regional_sales)
    )
    SELECT region,
           product,
           SUM(quantity) AS product_units,
           SUM(amount) AS product_sales
    FROM orders
    WHERE region IN (SELECT region FROM top_regions)
    GROUP BY region, product;

      可选的RECURSIVE修饰符将WITH从单纯的句法便利变成了一种在标准SQL中不能完成的特性。通过使用RECURSIVE,一个WITH查询可以引用它自己的输出。

    WITH RECURSIVE search_graph(id, link, data, depth) AS (
        SELECT g.id, g.link, g.data, 1
        FROM graph g
      UNION ALL
        SELECT g.id, g.link, g.data, sg.depth + 1
        FROM graph g, search_graph sg
        WHERE g.id = sg.link
    )
    SELECT * FROM search_graph;

      WITH查询的一个有用的特性是在每一次父查询的执行中它们通常只被计算一次,即使它们被父查询或兄弟WITH查询引用了超过一次。 因此,在多个地方需要的昂贵计算可以被放在一个WITH查询中来避免冗余工作。

      如果 WITH 查询是非递归和边际效应无关的(就是说,它是一个SELECT包含没有可变函数),则它可以合并到父查询中,允许两个查询级别的联合优化。 默认情况下,这发生在如果父查询仅引用 WITH查询一次的时候,而不是它引用WITH查询多于一次时。 

    WITH w AS (
        SELECT * FROM big_table
    )
    SELECT * FROM w WHERE key = 123;

      这个 WITH 查询将被合并,生成相同的执行计划为

    SELECT * FROM big_table WHERE key = 123;

      2.WITH中的数据修改

      在WITH中使用数据修改语句(INSERTUPDATEDELETE),这允许你在同一个查询中执行多个而不同操作。

    WITH moved_rows AS (
        DELETE FROM products
        WHERE
            "date" >= '2010-10-01' AND
            "date" < '2010-11-01'
        RETURNING *
    )
    INSERT INTO products_log
    SELECT * FROM moved_rows;

      这个查询实际上从products把行移动到products_logWITH中的DELETE删除来自products的指定行,以它的RETURNING子句返回它们的内容,并且接着主查询读该输出并将它插入到products_log

      3.WITH中的MATERIALIZED

    WITH w AS (
        SELECT * FROM big_table
    )
    SELECT * FROM w AS w1 JOIN w AS w2 ON w1.key = w2.ref
    WHERE w2.key = 123;

      WITH查询将被物化,生成一个big_table的临时拷贝,然后与其自身 — 联合,这样将不能从索引上获得任何好处。 如果写成下面的形式,这个查询将被执行得更有效率。

    WITH w AS NOT MATERIALIZED (
        SELECT * FROM big_table
    )
    SELECT * FROM w AS w1 JOIN w AS w2 ON w1.key = w2.ref
    WHERE w2.key = 123;

      所以父查询的限制可以直接应用于big_table的扫描。

      一个NOT MATERIALIZED 可能不理想的例子为:

    WITH w AS (
        SELECT key, very_expensive_function(val) as f FROM some_table
    )
    SELECT * FROM w AS w1 JOIN w AS w2 ON w1.f = w2.f;

      在这里,WITH查询的物化确保very_expensive_function每个表行只计算一次,而不是两次。

  • 相关阅读:
    【原创】用一个登陆的例子详细学习ObjectC基本语法
    一篇不错的讲解Java异常的文章(转载)
    在XML文件中定义动画(1)
    列表异步线程加载图片
    如何解决加载大图片时内存溢出的问题
    ImageView加载当地和网络图片
    不等号运算符<>
    vue回到顶部组件
    js实现多标签页效果
    微信小程序播放视频发送弹幕效果
  • 原文地址:https://www.cnblogs.com/ryjJava/p/14322082.html
Copyright © 2011-2022 走看看