<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ PostgreSQL - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ freeCodeCamp 是一个免费学习编程的开发者社区，涵盖 Python、HTML、CSS、React、Vue、BootStrap、JSON 教程等，还有活跃的技术论坛和丰富的社区活动，在你学习编程和找工作时为你提供建议和帮助。 ]]>
        </description>
        <link>https://www.freecodecamp.org/chinese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ PostgreSQL - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/chinese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 07 Jun 2026 14:16:14 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/chinese/news/tag/postgres/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ 播客 Ep. 27 对话资深 Web 开发者伍裕平：保持开放心态，成为终身学习者 ]]>
                </title>
                <description>
                    <![CDATA[ 今天的嘉宾伍裕平是一位非计算机专业科班出身的 Web 开发者，他在小学时开始对计算机和编程感兴趣，逐步学习了 Flash 和网页制作以及 Visual Basic、C 语言等等，在大学期间深入研究操作系统底层知识。 在毕业后因为对于软件开发的兴趣，他成为一名 Web 全栈工程师，参与移动互联网产品的开发。现在他就职于一家跨国银行。在节目中，他聊到职场新人如何成长、技术专家的思维方式以及银行业 IT 技术转型升级等等话题。 相信他保持开放心态、持续学习、终身学习的态度也会给你启发和动力，期待你关注我们的播客，并把节目分享给更多朋友。也欢迎你发邮件分享自己的故事，也许我们会邀请你作为 freeCodeCamp 播客的嘉宾。你可以在这篇文章 [https://www.freecodecamp.org/chinese/news/freecodecamp-podcast-in-chinese/] 中找到邮箱地址。 freeCodeCamp 最近上线了很多关于编程和英语的新课程，接下来 Miya 会专注于英语课程的编写，同时将新课程翻译为中文，中文播客会暂停一段时间，谢谢大家支持，期待第二季 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/interview-wu-yu-ping-web-development-in-banking-industry-and-life-long-learner/</link>
                <guid isPermaLink="false">65cf47a085add803f3c40d73</guid>
                
                    <category>
                        <![CDATA[ 播客 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web开发 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ 微服务 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ PostgreSQL ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Miya Liu ]]>
                </dc:creator>
                <pubDate>Thu, 15 Feb 2024 13:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2024/02/-----2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>今天的嘉宾伍裕平是一位非计算机专业科班出身的 Web 开发者，他在小学时开始对计算机和编程感兴趣，逐步学习了 Flash 和网页制作以及 Visual Basic、C 语言等等，在大学期间深入研究操作系统底层知识。</p><!--kg-card-begin: html--><iframe width="100%" height="180" frameborder="no" scrolling="no" seamless="" src="https://share.transistor.fm/e/9aa69240" title="嵌入内容" loading="lazy"></iframe><!--kg-card-end: html--><p>在毕业后因为对于软件开发的兴趣，他成为一名 Web 全栈工程师，参与移动互联网产品的开发。现在他就职于一家跨国银行。在节目中，他聊到职场新人如何成长、技术专家的思维方式以及银行业 IT 技术转型升级等等话题。</p><p>相信他保持开放心态、持续学习、终身学习的态度也会给你启发和动力，期待你关注我们的播客，并把节目分享给更多朋友。也欢迎你发邮件分享自己的故事，也许我们会邀请你作为 freeCodeCamp 播客的嘉宾。你可以在<a href="https://www.freecodecamp.org/chinese/news/freecodecamp-podcast-in-chinese/">这篇文章</a>中找到邮箱地址。</p><p>freeCodeCamp 最近上线了很多关于编程和英语的新课程，接下来 Miya 会专注于英语课程的编写，同时将新课程翻译为中文，中文播客会暂停一段时间，谢谢大家支持，期待第二季再见。也期待你把节目分享给朋友们，我们一起带给更多人启发和动力。</p><p>如果你感兴趣和我一起翻译新课程，请查看<a href="https://forum.freecodecamp.org/t/freecodecamp/512992">贡献指南</a>。</p><p>欢迎在 <a href="https://chinese.freecodecamp.org/">https://chinese.freecodecamp.org/</a> 查看更多免费的编程学习资源。</p><h2 id="-"><strong>主要话题</strong></h2><ul><li>04:17 对于编程从兴趣到职业</li><li>15:15 移动互联网行业 Web 开发</li><li>21:20 职场新人如何提升实践能力</li><li>31:58 银行业 IT 技术转型</li><li>39:23 微服务</li><li>47:10 跨国银行中的技术更新</li><li>1:01:10 安全与合规</li><li>1:07:12 数据库</li><li>1:16:31成为技术专家</li><li>1:28:41 外企的企业文化</li><li>1:35:02 养垂耳兔和练咏春拳</li><li>1:39:43 什么时候提问</li><li>1:44:42 保持开放心态和虚心学习</li></ul><h2 id="--1"><strong>提到的资源</strong></h2><ul><li><a href="https://www.freecodecamp.org/chinese/news/the-model-view-controller-pattern-mvc-architecture-and-frameworks-explained/">《MVC 架构详解》</a></li><li><a href="https://www.wikiwand.com/zh-sg/%E5%BE%AE%E6%9C%8D%E5%8B%99">微服务</a></li><li><a href="https://www.mysql.com/cn/">MySQL</a></li><li><a href="https://www.postgresql.org/">PostgreSQL</a>：<a href="https://www.freecodecamp.org/chinese/news/2021-postgres-1/">PostgreSQL 系列 4 篇文章</a></li><li><a href="https://en.uniapp.dcloud.io/">UniApp</a></li><li><a href="https://www.jeecg.com/">JEECG</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 基于流复制创建 PostgreSQL 15 从库 ]]>
                </title>
                <description>
                    <![CDATA[ 都说数据无价，本文就介绍一下如何快速拥有一个PostgreSQL的备库，从而实现主从数据库 。通常情况下，从库可以作为一个备份的存在（只读），当主库出现宕机后，我们可以快速把从库提升为主库（读写）。步骤并不复杂，一起来尝试一下吧。 创建用户，专门用来实现数据复制 create user replica with replication login password 'replication'; 检查postgresql.conf配置文件 wal_level = replica 检查pg_hba.conf权限配置文件 建议在最后追加一行host replication replica all md5，其中all也可以替换为从库所处机器的ip地址，比如 192.168.0.10/32 生成备份库  pg_basebackup -h 192.168.0.21 -p 54321 -U replica -R -P -v -C --slot=pgstandby1 -D /Users/liurui/pg2  * -R 说明会创建standby.signal文件，以及补充postgres ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/postgresql15-stream-replication/</link>
                <guid isPermaLink="false">639a7f69a7bffa07c7441624</guid>
                
                    <category>
                        <![CDATA[ PostgreSQL ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 牧云踏歌 ]]>
                </dc:creator>
                <pubDate>Thu, 15 Dec 2022 02:49:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2022/12/iShot2020-12-04-14.24.51.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>都说数据无价，本文就介绍一下如何快速拥有一个<code>PostgreSQL</code>的备库，从而实现<strong>主从数据库</strong>。通常情况下，从库可以作为一个备份的存在（只读），当主库出现宕机后，我们可以快速把从库提升为主库（读写）。步骤并不复杂，一起来尝试一下吧。</p>
<h3 id="">创建用户，专门用来实现数据复制</h3>
<pre><code>create user replica with replication login password 'replication';
</code></pre>
<h3 id="postgresqlconf">检查<code>postgresql.conf</code>配置文件</h3>
<p><code>wal_level = replica</code></p>
<h3 id="pg_hbaconf">检查<code>pg_hba.conf</code>权限配置文件</h3>
<p>建议在最后追加一行<code>host replication replica all md5</code>，其中<code>all</code>也可以替换为从库所处机器的<code>ip</code>地址，比如<code>192.168.0.10/32</code></p>
<h3 id="">生成备份库</h3>
<pre><code> pg_basebackup -h 192.168.0.21 -p 54321 -U replica -R -P -v -C --slot=pgstandby1 -D /Users/liurui/pg2
</code></pre>
<ul>
<li>-R 说明会创建<code>standby.signal</code>文件，以及补充<code>postgresql.auto.conf</code>的内容</li>
<li>-P 显示备份进度</li>
<li>-v 显示更加详细信息</li>
<li>-C 同时创建复制槽</li>
<li>--slot 指定复制槽的名字（一个备库一个名字）</li>
<li>-D 生成备库的路径</li>
</ul>
<blockquote>
<p>复制槽的好处<br>
主库的事务日志一直处于滚动消耗的状态，如果备库下线，随着主库频繁的数据变动，可能就会存在当备库重新上线后，已经找不到之前没有拉取的事务日志的情况（被主库回收掉了）。<br>
但是有了复制槽，主库就会为复制槽保留它没有消费的日志，等待它上线后进行消费。当然代价是对磁盘的消耗，不过只要备库不是永久丢失，磁盘消耗对于大部分场景来说不是问题。<br>
但是如果备库永久丢失了，要记得删除主库中对应的复制槽。删除复制槽的语句为<code>select pg_drop_replication_slot('pgstandby1');</code></p>
</blockquote>
<blockquote>
<p>注意<br>
备库的操作系统环境最好与主库一致，如果一个是Windows一个是Linux，几乎一定会遇到字符集不一致的问题，导致备库无法启动。</p>
</blockquote>
<h3 id="">启动备库</h3>
<pre><code>pg_ctl -D /Users/liurui/pg2 start
</code></pre>
<h3 id="">验证流复制可用性</h3>
<ul>
<li>在主库进行数据变动，在备库可进行观察</li>
<li>在主库执行<code>select * from pg_replication_slots;</code>能够观察到复制槽</li>
<li>在主库执行<code>select * from pg_stat_replication;</code>可以观察到备库连接情况，只有备库上线的情况下，该查询才会返回数据</li>
<li>顺便说一下，从库的数据目录会生成名为<code>postgresql.auto.conf</code>的文件（对应上面的<code>-R</code>参数），里面存放了主库的连接信息，感兴趣的小伙伴可以观察看看，但是这个文件不建议手动编辑。</li>
<li><strong>注意</strong>，这样创建的备库其实叫异步备库，极端情况下，备库的数据跟主库比是有一定延迟的，如果需要无延迟的备库，就需要启动<code>同步</code>模式，当然它会牺牲更多的性能，也要付出更高的运维成本，本文并不涉及<code>同步</code>模式的介绍。</li>
</ul>
<h3 id="">如何获得指定延迟时间的备库（可选）</h3>
<p>大部分情况下，备库与主库保持一致是我们需要的。但是有时候，我们也需要的也一个比主库有延迟的备库，比如<code>延迟三十分钟</code>，也就意味着，当主库的数据被不小心删除后，三十分钟内，我们都可以在备库里找到。此时需要在备库配置：</p>
<pre><code>recovery_min_apply_delay = 30min
</code></pre>
<h3 id="">手动把备库提升为主库</h3>
<p>备库平时只能作为只读数据库使用，因为可写数据是主库才有的特权。但是一旦主库挂掉，并且已知备库的数据足够完整的情况下，我们可以迅速把备库提升为主库。只要找到备库的文件路径，把里面的<code>standby.signal</code>文件删除即可。顺便说一下，这个文件是没有内容的，它是一个空文件，通过这个文件的存在来表明自己是个备库，所以删掉或者重命名该文件，都能把这个备库提升为主库。当然，别忘了删除该文件后，重启备库才能生效。</p>
<h3 id="docker">补充：在docker环境下生成备库</h3>
<ol>
<li>
<p>像平常在<code>docker</code>使用一样，启动一个数据库，当然要注意该备库的版本与主库保持一致。一个典型的yml文件如下：</p>
<pre><code>version: '3'
services:
 postgres15-bak:
  image: postgres:15.1
  ports:
   - 34325:5432
  volumes:
   - /root/docker/volume/postgres15:/var/lib/postgresql/data
</code></pre>
</li>
<li>
<p>使用<code>docker-compose</code>启动该镜像后，再通过<code>docker exec</code>进入它</p>
</li>
<li>
<p>切换用户：<code>su postgres</code></p>
</li>
<li>
<p>进入<code>postgres</code>拥有权限的路径：<code>cd /var/lib/postgresql/data</code></p>
</li>
<li>
<p>生成备库：<code>pg_basebackup -h 192.168.0.21 -p 54321 -U replica -R -P -v -C --slot=pgstandby1 -D ./bak</code> 此时备库路径就在<code>/var/lib/postgresql/data/bak</code>下</p>
</li>
<li>
<p>退出<code>docker</code>，回到宿主机，并关闭刚刚使用的<code>docker</code>镜像</p>
</li>
<li>
<p>在宿主机把刚才镜像映射的文件夹调整一下，以上面的<code>yml</code>文件为例，就应该先把<code>/root/docker/volume/postgres15/bak</code>文件夹拷贝出来，再把<code>/root/docker/volume/postgres15</code>文件夹删除掉，之后把刚拷贝出来的<code>bak</code>文件夹还原为<code>/root/docker/volume/postgres15</code>，此时该镜像映射的文件夹就是我们新产生的从库备份了。</p>
</li>
<li>
<p>启动上面的<code>docker</code>镜像。则从库已经接入主库。</p>
</li>
</ol>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 2021年了，你真的应该考虑PostgreSQL了（4·终章） ]]>
                </title>
                <description>
                    <![CDATA[ 本篇文章将会是这个系列的最后一篇。数据库是一门实践为王的技术，所以我无法通过寥寥几篇专栏就把PostgreSQL 给说清楚，更多有价值的功能及用法只能有待你自己去亲自动手尝试了。 今天我还会介绍一个属于PostgreSQL独有的特性，并且这个特性如同一把钥匙，可以给你打开一个崭新的数据库编程世界，至少我是这么认为的，那么我们赶紧开始吧。 SQL这种东西，本身是面向结果的，而不是面向过程的。这跟传统的编程语言有很大的区别，比如你在使用JavaScript、Java 时，这些语言都是基于过程的，你要一步一步通过代码表达式把要做的逻辑过程编写出来，让计算机理解。而SQL 是不具备这种能力的，虽然它看起来更高级，你只需要对着数据库说“要有光”(select light from universe)，“光”就来了。 但是不可否认，SQL语言的表达能力是有限的，有些复杂的逻辑我们无法依赖SQL直接实现。比如：计算当前时间是本年度的第几周，这显然已经超出了SQL 的能力范围。所以数据库的创造者们，给数据库增加了SQL之外的能力，也就是Procedural Language（过程语言）简称PL  ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/2021-postgres-4/</link>
                <guid isPermaLink="false">60042f345f61e30501b5bdae</guid>
                
                    <category>
                        <![CDATA[ PostgreSQL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Java ]]>
                    </category>
                
                    <category>
                        <![CDATA[ 后端开发 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 牧云踏歌 ]]>
                </dc:creator>
                <pubDate>Sun, 17 Jan 2021 12:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/01/iShot2020-12-04-14.24.51.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>本篇文章将会是这个系列的最后一篇。数据库是一门实践为王的技术，所以我无法通过寥寥几篇专栏就把<code>PostgreSQL</code>给说清楚，更多有价值的功能及用法只能有待你自己去亲自动手尝试了。</p><p>今天我还会介绍一个属于<code>PostgreSQL</code>独有的特性，并且这个特性如同一把钥匙，可以给你打开一个崭新的数据库编程世界，<s>至少我是这么认为的</s>，那么我们赶紧开始吧。</p><p><code>SQL</code>这种东西，本身是面向结果的，而不是面向过程的。这跟传统的编程语言有很大的区别，比如你在使用<code>JavaScript</code>、<code>Java</code>时，这些语言都是基于过程的，你要一步一步通过代码表达式把要做的逻辑过程编写出来，让计算机理解。而<code>SQL</code>是不具备这种能力的，虽然它看起来更高级，你只需要对着数据库说“要有光”(<code>select light from universe</code>)，“光”就来了。</p><p>但是不可否认，<code>SQL</code>语言的表达能力是有限的，有些复杂的逻辑我们无法依赖<code>SQL</code>直接实现。比如：计算当前时间是本年度的第几周，这显然已经超出了<code>SQL</code>的能力范围。所以数据库的创造者们，给数据库增加了<code>SQL</code>之外的能力，也就是<code>Procedural Language</code>（过程语言）简称<code>PL</code>。这种过程语言就给开发者提供了传统编程语言的逻辑方式，方便我们在数据里实现一种叫<code>存储过程</code>/<code>函数</code>的东西，进而拓展了数据库本身的逻辑能力。</p><p>几乎每个关系型数据库都有自己的<code>PL</code>实现，比如<code>Oracle</code>的<code>PL/SQL</code>、<code>SQL Server</code>的<code>T-SQL</code>，而在<code>PostgreSQL</code>中，提供的就是<code>PL/pgSQL</code>。</p><p>这当然也不是什么新鲜事。作为本系列的最后一篇，如果只是讲讲<code>PL/pgSQL</code>未免有些平淡了。</p><p>容我给你展示一组清单：</p><ul><li>PL/Java</li><li>PL/PHP</li><li>PL/Perl</li><li>PL/Python</li><li>PL/V8</li></ul><p>结合前文所述，您大概已经猜到了。<code>PL/xxx</code>其实就是在说用基于某个语言实现数据库里的存储过程。换句话说，我们可以用自己熟知的高级语言，如：<code>Java</code>、<code>PHP</code>、<code>Python</code>来编写数据库的存储过程。当然了，这个功能是<code>PostgreSQL</code>独有的，别的数据库可享受不到。至于<code>PL/V8</code>，如果你熟悉前端开发的话，应该不难猜出这里说的是<code>JavaScript</code>的<code>V8</code>引擎。</p><p>下面我就用<code>PL/Python</code>来演示下，如何用<code>Python3</code>来开发<code>PostgreSQL</code>的存储过程。</p><p>首先需要在数据库服务器上安装<code>Python3</code>，然后再安装<code>PostgreSQL</code>的<code>Python3</code>扩展。以<code>ubuntu</code>为例，你需要执行：</p><pre><code class="language-sh">apt-get install postgresql-plpython3-13
</code></pre><p>注意最后的数字<code>13</code>，应该与你本地的<code>PostgreSQL</code>版本相对应。一旦扩展安装关闭，就可以通过一条<code>SQL</code>语句，在数据库中开启对应的扩展功能，你需要执行。</p><pre><code class="language-sql">create extension "plpython3u";
</code></pre><p>下面我们尝试创建一个存储过程（其实称为“函数”可能更准确，不过“存储过程”比“函数”更贴近数据库的专有词汇，为了方便大家理解，我采用了“存储过程”的说法）。</p><pre><code class="language-sql">create function pymax(a integer, b integer)
  returns integer
language plpython3u
as $$
if a &gt; b:
    return a
return b
$$;
</code></pre><p>这是一个简单的比较两个整型大小的存储过程，本身没什么技术含量。需要特别注意的是<code>$$</code>之间的代码段是通过<code>language</code>指定的，当我们指定了<code>plpython3u</code>后，就可以用<code>Python3</code>来编写函数了。</p><p>简单执行测试一下:</p><pre><code class="language-sql">studypg=# select pymax(2, 3);
 pymax
-------
     3
(1 row)
</code></pre><p>可以看到函数顺利执行成功了。</p><p>聪明的你可能会说，能利用上<code>Python</code>的语言本身固然有点意思，但是实际价值却不大。要是能利用上<code>Python</code>的生态，那才是真的强。答案当然是<strong>Yes</strong>啦。</p><p>众所周知，最近几年<code>Python</code>在机器学习领域可谓是独领风骚。这得益于其多年在数学领域的积累，而<code>numpy</code>这个包，更是所有数学工作者的最爱。下面我就用<code>numpy</code>演示，如何在<code>PostgreSQL</code>中使用<code>Python</code>的强大生态。</p><p>首先安装<code>numpy</code>包，执行：</p><pre><code class="language-sh">pip3 install numpy
</code></pre><p>然后我们创建一个存储过程，用来计算以e为底的自然数对数，语句如下：</p><pre><code class="language-sql">create or replace function pylog(x float)
  returns float
language plpython3u
as $$
import numpy as np

return np.log(x)
$$;
</code></pre><p>看下执行结果：</p><pre><code class="language-sql">studypg=# select pylog(1);
 pylog
-------
     0
(1 row)

studypg=# select pylog(0.1);
       pylog
-------------------
 -2.30258509299405
(1 row)
</code></pre><p>非常完美，借助<code>Python</code>生态的力量，我们仅用几句话就实现了原本<code>SQL</code>根本无法实现的功能。其实这还只是冰山一角。笔者甚至通过<code>Python</code>版的数据库函数作为数据库表的触发器，拦截到数据的变化，直接把变化信息转发到<code>MQTT</code>服务器，从而让其他外部应用，可以通过对<code>MQTT</code>消息的订阅，得到数据变化的推送信息。</p><p>好了，关于<code>PostgreSQL</code>中神奇的存储过程，就介绍到这里了。其实在<code>PostgreSQL</code>中还有很多神奇的事情值得挖掘，比如触发器，<code>PostgreSQL</code>不光可以拦截<code>DML</code>还可以拦截<code>DDL</code>；还有外部数据源<code>FDW</code>，<code>PostgreSQL</code>中可以引用多种外部数据，包括<code>MySQL</code>、<code>Oracle</code>等主流关系型数据库，甚至还支持<code>Redis</code>、<code>MongoDB</code>等非关系型数据库。总之，只有想不到，没有做不到。</p><p>关于<code>PostgreSQL</code>的系列文章至此就结束了。希望我的文章能激发出你对数据库的兴趣，愿这门悠久而强大的技术能够在你的工作中起到一些积极作用。最重要的，请一定要多实践。我们下个话题再见😃</p><p><strong>推荐阅读本系列的其他文章：</strong></p><ul><li><a href="https://chinese.freecodecamp.org/news/2021-postgres-1/">2021年了，你真的应该考虑PostgreSQL了（1）</a></li><li><a href="https://chinese.freecodecamp.org/news/2021-postgres-2/">2021年了，你真的应该考虑PostgreSQL了（2）</a></li><li><a href="https://chinese.freecodecamp.org/news/2021-postgres-3/">2021年了，你真的应该考虑PostgreSQL了（3）</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 2021年了，你真的应该考虑PostgreSQL了（3） ]]>
                </title>
                <description>
                    <![CDATA[ 前两期我们已经做了充足的铺垫，向你描绘了一个强大的数据库——PostgreSQL。通过之前的实战，你应该感受到SQL 是一门富有魅力的强大技术。今天，我将为你展示一个属于PostgreSQL 独有的特性——表继承，这是我最爱的特性之一，它非常实用。一旦你掌握了这项特性，并把它运用于你的项目中，一定会大呼过瘾的。 想象我们在做一个企业业务管理系统，需要为客户提供各种业务的增删改查功能。比如进销存这样的系统，我们要管理采购、入库、销售、出库 等一系列的业务，而这些业务通常会有一些通用的设计，比如制单人、制单时间等等。 采用传统数据库的时候，我们通常就会在所有的业务表都添加这些相同的字段，虽然繁琐点，也并非无法忍受。但是当你积攒了成百个这种业务时，如果再想增加个字段，比如增加个 修改人、修改时间什么的，那场面就不太美妙了。 还有另外一个场景，企业的业务，几乎每个单据（业务），都会有一个叫编号 的东西，比如：订单编号、物流单号、支付流水号。这时，如果你的产品经理跟你提个需求，想做一个万能搜索，用户可以在文本框里随便输入一个编号，就能对系统中所有的业务单据编号进行模糊匹配，你打算怎么设计呢 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/2021-postgres-3/</link>
                <guid isPermaLink="false">5fe86f6239641a0517d52631</guid>
                
                    <category>
                        <![CDATA[ PostgreSQL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Java ]]>
                    </category>
                
                    <category>
                        <![CDATA[ 后端开发 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 牧云踏歌 ]]>
                </dc:creator>
                <pubDate>Sun, 27 Dec 2020 11:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2020/12/iShot2020-12-04-14.24.51-2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>前两期我们已经做了充足的铺垫，向你描绘了一个强大的数据库——<code>PostgreSQL</code>。通过之前的实战，你应该感受到<code>SQL</code>是一门富有魅力的强大技术。今天，我将为你展示一个属于<code>PostgreSQL</code>独有的特性——表继承，这是我最爱的特性之一，它非常实用。一旦你掌握了这项特性，并把它运用于你的项目中，一定会大呼过瘾的。</p>
<p>想象我们在做一个企业业务管理系统，需要为客户提供各种业务的增删改查功能。比如进销存这样的系统，我们要管理<code>采购</code>、<code>入库</code>、<code>销售</code>、<code>出库</code>等一系列的业务，而这些业务通常会有一些通用的设计，比如<code>制单人</code>、<code>制单时间</code>等等。</p>
<p>采用传统数据库的时候，我们通常就会在所有的业务表都添加这些相同的字段，虽然繁琐点，也并非无法忍受。但是当你积攒了成百个这种业务时，如果再想增加个字段，比如增加个<code>修改人</code>、<code>修改时间</code>什么的，那场面就不太美妙了。</p>
<p>还有另外一个场景，企业的业务，几乎每个单据（业务），都会有一个叫<code>编号</code>的东西，比如：订单编号、物流单号、支付流水号。这时，如果你的产品经理跟你提个需求，想做一个万能搜索，用户可以在文本框里随便输入一个编号，就能对系统中所有的业务单据编号进行模糊匹配，你打算怎么设计呢？</p>
<p>来看看在拥有<code>表继承</code>特性的<code>PostgreSQL</code>你该怎么做吧。</p>
<ol>
<li>
<p>创建业务基础表（父表），仅需包含几个关键字段即可：</p>
<pre><code class="language-sql">create table basic_business
(
	id varchar default gen_random_uuid()
		constraint basic_business_pk
			primary key,
	v_code varchar,
	t_create timestamp default now()
);
</code></pre>
<p>为了演示方便，这里我只准备三个字段，分别是：主键（uuid）、编码、创建时间。</p>
<blockquote>
<p>也许你注意到了<code>varchar</code>类型我们并没有指定长度，这又是一个<code>PostgreSQL</code>的精彩特性，<code>varchar</code>类型的长度是可选的，并且长度仅仅是一种约束，而不会对性能产生丝毫影响。所以大胆地采用无长度限制能够在不牺牲性能的情况下帮我们免去很多烦恼——我猜你肯定经历过录入数据超长引起的bug。</p>
</blockquote>
</li>
<li>
<p>创建业务表A：</p>
<pre><code class="language-sql">create table a_business
(
	a_column varchar
) inherits (basic_business);
</code></pre>
<p>这里我们通过<code>inherits</code>关键字，声明了<code>a_business</code>对<code>basic_business</code>的继承关系。因为这种继承关系的存在，<code>basic_business</code>表中已经存在的字段，无需再次创建，我们仅需要在<code>a_business</code>中关注该业务独有的字段即可。</p>
</li>
<li>
<p>需要注意一点，表继承关系，可以传递<code>默认值</code>、<code>非空约束</code>等，但是主键行为不会传递，所以针对创建成功的<code>a_business</code>表，我们还要给他补一个主键声明：</p>
<pre><code class="language-sql">alter table a_business
	add constraint a_business_pk
		primary key (id);
</code></pre>
</li>
<li>
<p>同样的，我们也准备一个业务B的表<code>b_business</code>，方式跟A一样，就不再赘述了。最后我们获得了如下图展示的三张表：</p>
<p><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/71d38eed-c9d9-45a8-a93a-8bd60e8bac4c-1.jpg" alt="71d38eed-c9d9-45a8-a93a-8bd60e8bac4c-1" width="824" height="812" loading="lazy"></p>
</li>
<li>
<p>下面尝试在<code>a_business</code>、<code>b_business</code>两个表中分别插入一些数据：</p>
<pre><code class="language-sql">insert into a_business (v_code, a_column) values ('A0001','test_1');
insert into a_business (v_code, a_column) values ('A0002','test_2');
insert into a_business (v_code, a_column) values ('A0003','test_3');

insert into b_business (v_code, b_column) values ('B0001','test_1');
insert into b_business (v_code, b_column) values ('B0002','test_2');
insert into b_business (v_code, b_column) values ('B0003','test_3');
</code></pre>
</li>
<li>
<p>我猜你已经迫不及待想去<code>select</code>一下<code>basic_business</code>了吧，那咱们赶紧来查看一下：</p>
<pre><code class="language-sql">select * from basic_business;
</code></pre>
<p>你将会得到如下结果：</p>
<p><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/583f6958-3f33-4cf4-9aca-6b3046d8236d.jpg" alt="583f6958-3f33-4cf4-9aca-6b3046d8236d" width="1560" height="326" loading="lazy"></p>
<p>可以看到我们插入在<code>a_business</code>及<code>b_business</code>中的数据都被查询到了。并且由于<code>basic_business</code>的字段只有三个，所以结果返回的也是这三个字段。</p>
<p>是不是有点意思呢？更精彩的还在后面。</p>
<p>当我们尝试对<code>basic_business</code>追加一个字段，比如增加一个<code>i_status</code>用来标记单据状态，并且我还给这个字段指定了一个默认值<code>0</code>。</p>
<pre><code class="language-sql">alter table basic_business
	add i_status int default 0;
</code></pre>
<p>这个时候，当我们回过头来<code>select</code>任意一个业务表的时候，你会惊喜的发现，业务表也会相应的追加字段，并且连默认值都准备就绪了。</p>
<pre><code class="language-sql">select * from a_business;
</code></pre>
<p>你会看到如下结果：</p>
<p><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/52b0cf1c-9019-488e-8fd7-dc59f4de11a7.jpg" alt="52b0cf1c-9019-488e-8fd7-dc59f4de11a7" width="1932" height="192" loading="lazy"></p>
<p>甚至当你觉得<code>basic_business</code>字段需要调整一下，重命名或者是改个类型，也都没有关系，比如我们可以这样：</p>
<pre><code class="language-sql">alter table basic_business rename column v_code to t_code;
alter table basic_business alter column t_code type text using t_code::text;
</code></pre>
<p>这个时候，我们再查询下<code>b_business</code>看看效果</p>
<pre><code class="language-sql">select * from b_business;
</code></pre>
<p>结果如下：</p>
<p><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/50d008d0-d035-4286-9237-7cdca87251b2.jpg" alt="50d008d0-d035-4286-9237-7cdca87251b2" width="2000" height="177" loading="lazy"></p>
<p>怎么样？是不是所有的结果都与我们期望的一样。</p>
<blockquote>
<p>顺便说一下，我们刚才把一个<code>varchar</code>类型改成了<code>text</code>，其实这是一种几乎无意义的操作。在<code>PostgreSQL</code>中<code>varchar</code>就是<code>text</code>另一种叫法。他俩唯一的区别就是<code>varchar</code>可以声明长度限制，仅此而已。</p>
</blockquote>
<p>爱动脑筋的你，是不是会问这么一个问题，如果我们在子表，也就是<code>a_business</code>中修改一个父表带过来的字段会怎么样呢？咱们就来试试看：</p>
<pre><code class="language-sql">alter table a_business alter column t_code type varchar using t_code::varchar
</code></pre>
<p>当我们打算把<code>a_business</code>表中的<code>t_code</code>类型从<code>text</code>改为<code>varchar</code>时，<code>PostgreSQL</code>给出了一个报错：</p>
<pre><code class="language-sql">ERROR: cannot alter inherited column "t_code"
</code></pre>
<p>这我们就明白了，对子表来说，继承而来的字段是不允许修改的。其实这是完全符合直觉的，毕竟如果子表可以二次定义继承字段的话，假设父表也对该字段做了变更，系统就不知道以谁为准了。所以最佳实现方式，就是单向传递，以避免潜在的冲突。</p>
</li>
<li>
<p>下面让我们来实现之前描述的第二个业务场景——通过对父表的<code>t_code</code>的模糊查询，同时对多个业务进行数据匹配：</p>
<pre><code class="language-sql">select * from basic_business where t_code like '%01%';
</code></pre>
<p>结果如下：</p>
<p><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/24f5315e-4fa1-41da-84ac-a2b2e31cc734.jpg" alt="24f5315e-4fa1-41da-84ac-a2b2e31cc734" width="1854" height="146" loading="lazy"></p>
<p>我们已经读到了分别位于<code>a_business</code>和<code>b_business</code>的两条数据。结果是不是很美妙呢？以后就是有再多的子表都不怕，只要都是继承<code>basic_business</code>的，我们都能查出来客户想要的数据。甚至不需要怎么修改代码。</p>
<p>你可能会问了，单看上面两行数据，并没有办法明确标记出该行数据具体属于哪个表呢？不着急，<code>PostgreSQL</code>已经替我们想到了，如果想多查询一列，用以显示具体该行数据的事实归属，我们可以这样做：</p>
<pre><code class="language-sql">select *,TABLEOID::regclass from basic_business where t_code like '%01%';
</code></pre>
<p>这样结果就多了一列，如图：</p>
<p><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/d7371289-9e6d-42d3-a47e-e78a8bc2a413.jpg" alt="d7371289-9e6d-42d3-a47e-e78a8bc2a413" width="2000" height="133" loading="lazy"></p>
<p>讲到这里你应该明白了，数据事实上永远只有一份，并且只是存在于具体的子表中。之所以查询父表能够看到子表的数据，只是<code>PostgreSQL</code>帮我们做的一点小魔法，这说起来有点像一个<code>union</code>了好多表的视图。</p>
</li>
<li>
<p>假设我查询父表的时候，不想带出子表的数据，该怎么做呢？其实也很简单，一个关键字的事：</p>
<pre><code class="language-sql">select * from only basic_business;
</code></pre>
<p>这样你就只会获取到明确<code>insert</code>到<code>basic_business</code>表中的数据了。</p>
</li>
</ol>
<h4 id="">总结</h4>
<p>表继承功能算不上有很强技术储备的设计，但却异常实用。除了上面演示的抽象业务通用字段，其实还有好多地方可以用上这个特性，比如软删除、跟第三方对接数据（你控制父表，他控制子表）等等，小伙伴们还是开动脑筋自己多多尝试一下吧。<br>
关于<code>PostgreSQL</code>表继承特性，今天就先介绍到这里。我想你应该体会到作为一款关系型数据库，<code>PostgreSQL</code>提供了不少颇具巧思的设计，以方便我们在实际业务场景中使用它。更多<code>PostgreSQL</code>实用特性，欢迎你继续关注我的专栏，咱们下期再见。</p>
<!--kg-card-end: markdown--><p><strong>推荐阅读本系列的其他文章：</strong></p><ul><li><a href="https://chinese.freecodecamp.org/news/2021-postgres-1/">2021年了，你真的应该考虑PostgreSQL了（1）</a></li><li><a href="https://chinese.freecodecamp.org/news/2021-postgres-2/">2021年了，你真的应该考虑PostgreSQL了（2）</a></li><li><a href="https://chinese.freecodecamp.org/news/2021-postgres-4/">2021年了，你真的应该考虑PostgreSQL了（4·终章）</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 2021年了，你真的应该考虑PostgreSQL了（2） ]]>
                </title>
                <description>
                    <![CDATA[ 毋庸置疑，SQL绝对是人类计算机发展史上最伟大的发明之一。这门存在了近半个世纪的技术，即使在大数据时代的当下依然扮演着重要的角色。像什么Flink、Pulsar 、Cassandra这样炙手可热的技术，又有哪个不支持SQL呢。可是即使SQL重要如此，还有好多小伙伴觉得SQL是一门过时的技术，因而不愿意花精力去学。更有一众 ORM框架为了追求面向对象的极致，掩盖了太多SQL之美，这真是我不乐见的。 首先，我必须强调，SQL虽是一门古老的技术，但却并非停滞不前。看下历代SQL标准年表： > SQL-86  SQL-89  SQL-92  SQL:1999  SQL:2003  SQL:2006  SQL:2008  SQL:2011   SQL:2016 标准这种东西迭代太快也不行，不然就算程序员们的头发能受了，数据库厂家也受不了。所以目前SQL 标准这种稳健的迭代是比较正确的做法。但是，即使是这样，数据库厂家们也没能跟上节奏，至今没有任何一家数据库产品声称完全符合SQL:2016的核心特性。 那么数据库里的优等生，我们的主角PostgreSQL表现得到底怎么样呢？ > As  ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/2021-postgres-2/</link>
                <guid isPermaLink="false">5fd7662439641a0517d51d9e</guid>
                
                    <category>
                        <![CDATA[ PostgreSQL ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 牧云踏歌 ]]>
                </dc:creator>
                <pubDate>Mon, 14 Dec 2020 11:27:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2020/12/iShot2020-12-04-14.24.51-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>毋庸置疑，<code>SQL</code>绝对是人类计算机发展史上最伟大的发明之一。这门存在了近半个世纪的技术，即使在大数据时代的当下依然扮演着重要的角色。像什么<code>Flink</code>、<code>Pulsar</code>、<code>Cassandra</code>这样炙手可热的技术，又有哪个不支持<code>SQL</code>呢。可是即使<code>SQL</code>重要如此，还有好多小伙伴觉得<code>SQL</code>是一门过时的技术，因而不愿意花精力去学。更有一众<code>ORM</code>框架为了追求面向对象的极致，掩盖了太多<code>SQL</code>之美，这真是我不乐见的。</p>
<p>首先，我必须强调，<code>SQL</code>虽是一门古老的技术，但却并非停滞不前。看下历代<code>SQL</code>标准年表：</p>
<blockquote>
<p><code>SQL-86</code> <code>SQL-89</code> <code>SQL-92</code> <code>SQL:1999</code> <code>SQL:2003</code> <code>SQL:2006</code> <code>SQL:2008</code> <code>SQL:2011</code> <code>SQL:2016</code></p>
</blockquote>
<p>标准这种东西迭代太快也不行，不然就算程序员们的头发能受了，数据库厂家也受不了。所以目前<code>SQL</code>标准这种稳健的迭代是比较正确的做法。但是，即使是这样，数据库厂家们也没能跟上节奏，至今没有任何一家数据库产品声称完全符合<code>SQL:2016</code>的核心特性。</p>
<p>那么数据库里的优等生，我们的主角<code>PostgreSQL</code>表现得到底怎么样呢？</p>
<blockquote>
<p>As of the version 13 release in September 2020, PostgreSQL conforms to at least 170 O of the 179 mandatory features for SQL:2016 Core conformance. As of this writing, no relational database meets full conformance with this standard.</p>
</blockquote>
<p>也就是说目前<code>SQL:2016</code>标准中的核心标准中的<strong>179</strong>项特性，<code>PostgreSQL</code>至少实现了<strong>170</strong>项，虽说离“完全体”还有一点差距，但是考虑到至今也没有任何一个关系型数据能够完全吻合标准，<code>PostgreSQL</code>的表现还是相当不错的。如果你感兴趣的话，可以看看其他数据库的标准完成度，基本都还差得远呢，甚至有些数据库因为实在是跟不上标准，竟然对此有点讳莫如深了。</p>
<p><strong>关于<code>SQL</code>的技艺展示，没有几本大部头的书是讲不完的。本文将从<code>PostgreSQL</code>入手，展示几个在实际项目中会用到的<code>SQL</code>特性。这些特性可能并非<code>PostgreSQL</code>独有，也并不是只有最新版本的<code>PostgreSQL</code>才支持。关于<code>PostgreSQL</code>独家特性展示，我将放在下一期的文章中。</strong></p>
<hr>
<p>想象这样一个表（表名:score），罗列了不同同学、不同课程的成绩单。<s>现实场景中，人员信息、课程信息可能都需要单独的表进行存放，成绩单应该通过人员ID、课程ID字段对前两者进行关联。但是本文着重介绍<code>PostgreSQL</code>的特性，为了大家阅读方便，采用了这个非标准范式的设计方案。</s></p>
<table>
<thead>
<tr>
<th style="text-align:left">id</th>
<th style="text-align:left">i_score</th>
<th style="text-align:left">v_name</th>
<th style="text-align:left">v_course</th>
<th style="text-align:left">v_type</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">981222c9aa8e</td>
<td style="text-align:left">78</td>
<td style="text-align:left">张无忌</td>
<td style="text-align:left">语文</td>
<td style="text-align:left">文</td>
</tr>
<tr>
<td style="text-align:left">b7e321377c21</td>
<td style="text-align:left">73</td>
<td style="text-align:left">张无忌</td>
<td style="text-align:left">数学</td>
<td style="text-align:left">理</td>
</tr>
<tr>
<td style="text-align:left">311365068bdc</td>
<td style="text-align:left">82</td>
<td style="text-align:left">张无忌</td>
<td style="text-align:left">英语</td>
<td style="text-align:left">文</td>
</tr>
<tr>
<td style="text-align:left">293721bcb0f0</td>
<td style="text-align:left">61</td>
<td style="text-align:left">张无忌</td>
<td style="text-align:left">物理</td>
<td style="text-align:left">理</td>
</tr>
<tr>
<td style="text-align:left">751567a4724e</td>
<td style="text-align:left">81</td>
<td style="text-align:left">令狐冲</td>
<td style="text-align:left">语文</td>
<td style="text-align:left">文</td>
</tr>
<tr>
<td style="text-align:left">0f639b6c2cf6</td>
<td style="text-align:left">68</td>
<td style="text-align:left">令狐冲</td>
<td style="text-align:left">数学</td>
<td style="text-align:left">理</td>
</tr>
<tr>
<td style="text-align:left">88edf8e530ad</td>
<td style="text-align:left">77</td>
<td style="text-align:left">令狐冲</td>
<td style="text-align:left">英语</td>
<td style="text-align:left">文</td>
</tr>
<tr>
<td style="text-align:left">a841d6175683</td>
<td style="text-align:left">83</td>
<td style="text-align:left">令狐冲</td>
<td style="text-align:left">物理</td>
<td style="text-align:left">理</td>
</tr>
<tr>
<td style="text-align:left">8e0490684601</td>
<td style="text-align:left">66</td>
<td style="text-align:left">乔峰</td>
<td style="text-align:left">语文</td>
<td style="text-align:left">文</td>
</tr>
<tr>
<td style="text-align:left">50167805bbfc</td>
<td style="text-align:left">94</td>
<td style="text-align:left">乔峰</td>
<td style="text-align:left">数学</td>
<td style="text-align:left">理</td>
</tr>
<tr>
<td style="text-align:left">261f0f9de93b</td>
<td style="text-align:left">76</td>
<td style="text-align:left">乔峰</td>
<td style="text-align:left">英语</td>
<td style="text-align:left">文</td>
</tr>
<tr>
<td style="text-align:left">18bb6bfafdf6</td>
<td style="text-align:left">95</td>
<td style="text-align:left">乔峰</td>
<td style="text-align:left">物理</td>
<td style="text-align:left">理</td>
</tr>
</tbody>
</table>
<h4 id="1">需求1. 找出每门课程的第一名</h4>
<p>目标结果：</p>
<table>
<thead>
<tr>
<th style="text-align:left">id</th>
<th style="text-align:left">i_score</th>
<th style="text-align:left">v_name</th>
<th style="text-align:left">v_course</th>
<th style="text-align:left">v_type</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">311365068bdc</td>
<td style="text-align:left">82</td>
<td style="text-align:left">张无忌</td>
<td style="text-align:left">英语</td>
<td style="text-align:left">文</td>
</tr>
<tr>
<td style="text-align:left">751567a4724e</td>
<td style="text-align:left">81</td>
<td style="text-align:left">令狐冲</td>
<td style="text-align:left">语文</td>
<td style="text-align:left">文</td>
</tr>
<tr>
<td style="text-align:left">50167805bbfc</td>
<td style="text-align:left">94</td>
<td style="text-align:left">乔峰</td>
<td style="text-align:left">数学</td>
<td style="text-align:left">理</td>
</tr>
<tr>
<td style="text-align:left">18bb6bfafdf6</td>
<td style="text-align:left">95</td>
<td style="text-align:left">乔峰</td>
<td style="text-align:left">物理</td>
<td style="text-align:left">理</td>
</tr>
</tbody>
</table>
<p>传统做法：</p>
<pre><code class="language-sql">select a.*
from score as a
         join (
    select v_course, max(i_score) as i_score
    from score
    group by v_course
) b on a.v_course = b.v_course and a.i_score = b.i_score;
</code></pre>
<p><code>PostgreSQL</code>做法：</p>
<pre><code class="language-sql">select distinct on (v_course) * from score order by v_course, i_score desc;
</code></pre>
<p>怎么样？本来需要子查询<code>join</code>一下才能解决的问题，<code>PostgreSQL</code>轻松一行搞定。</p>
<h4 id="2">需求2. 查询每名同学的总平均分、文科平局分、理科平均分</h4>
<p>目标结果：</p>
<table>
<thead>
<tr>
<th style="text-align:left">v_name</th>
<th style="text-align:left">总平均分</th>
<th style="text-align:left">文科平均</th>
<th style="text-align:left">理科平均</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">乔峰</td>
<td style="text-align:left">82.75</td>
<td style="text-align:left">71</td>
<td style="text-align:left">94.5</td>
</tr>
<tr>
<td style="text-align:left">令狐冲</td>
<td style="text-align:left">77.25</td>
<td style="text-align:left">79</td>
<td style="text-align:left">75.5</td>
</tr>
<tr>
<td style="text-align:left">张无忌</td>
<td style="text-align:left">73.5</td>
<td style="text-align:left">80</td>
<td style="text-align:left">67</td>
</tr>
</tbody>
</table>
<p>传统做法：</p>
<pre><code class="language-sql">select v_name,
       avg(i_score) as 总平均分,
       sum(case when v_type ='文' then i_score else 0 end)/sum(case when v_type ='文' then 1.0 else 0 end)  文科平均,
       sum(case when v_type ='理' then i_score else 0 end)/sum(case when v_type ='理' then 1.0 else 0 end)  理科平均
from score
group by v_name
</code></pre>
<p>说实话，这样写看着也还行，但是<code>case when</code>这种东西对索引实在是不够友好，在应对大数据量的时候会力不从心。</p>
<p><code>PostgreSQL</code>做法:</p>
<pre><code class="language-sql">select v_name,
       avg(i_score) as 总平均分,
       avg(i_score) filter ( where v_type = '文' ) as 文科平均,
       avg(i_score) filter ( where v_type = '理' ) as 理科平均
from score
group by v_name
</code></pre>
<p>可读性立马高很多，隐隐有种<code>SQL</code>艺术的感觉，执行效率也要比前者高。</p>
<h4 id="3">需求3. 查询每名同学的成绩与该课程平均分的差异</h4>
<p>目标结果：</p>
<table>
<thead>
<tr>
<th style="text-align:left">id</th>
<th style="text-align:left">i_score</th>
<th style="text-align:left">v_name</th>
<th style="text-align:left">v_course</th>
<th style="text-align:left">v_type</th>
<th style="text-align:left">该课平均</th>
<th style="text-align:left">成绩差</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">0f639b6c2cf6</td>
<td style="text-align:left">68</td>
<td style="text-align:left">令狐冲</td>
<td style="text-align:left">数学</td>
<td style="text-align:left">理</td>
<td style="text-align:left">78.33</td>
<td style="text-align:left">-10.33</td>
</tr>
<tr>
<td style="text-align:left">18bb6bfafdf6</td>
<td style="text-align:left">95</td>
<td style="text-align:left">乔峰</td>
<td style="text-align:left">物理</td>
<td style="text-align:left">理</td>
<td style="text-align:left">79.67</td>
<td style="text-align:left">15.33</td>
</tr>
<tr>
<td style="text-align:left">261f0f9de93b</td>
<td style="text-align:left">76</td>
<td style="text-align:left">乔峰</td>
<td style="text-align:left">英语</td>
<td style="text-align:left">文</td>
<td style="text-align:left">78.33</td>
<td style="text-align:left">-2.33</td>
</tr>
<tr>
<td style="text-align:left">293721bcb0f0</td>
<td style="text-align:left">61</td>
<td style="text-align:left">张无忌</td>
<td style="text-align:left">物理</td>
<td style="text-align:left">理</td>
<td style="text-align:left">79.67</td>
<td style="text-align:left">-18.67</td>
</tr>
<tr>
<td style="text-align:left">311365068bdc</td>
<td style="text-align:left">82</td>
<td style="text-align:left">张无忌</td>
<td style="text-align:left">英语</td>
<td style="text-align:left">文</td>
<td style="text-align:left">78.33</td>
<td style="text-align:left">3.67</td>
</tr>
<tr>
<td style="text-align:left">50167805bbfc</td>
<td style="text-align:left">94</td>
<td style="text-align:left">乔峰</td>
<td style="text-align:left">数学</td>
<td style="text-align:left">理</td>
<td style="text-align:left">78.33</td>
<td style="text-align:left">15.67</td>
</tr>
<tr>
<td style="text-align:left">751567a4724e</td>
<td style="text-align:left">81</td>
<td style="text-align:left">令狐冲</td>
<td style="text-align:left">语文</td>
<td style="text-align:left">文</td>
<td style="text-align:left">75</td>
<td style="text-align:left">6</td>
</tr>
<tr>
<td style="text-align:left">88edf8e530ad</td>
<td style="text-align:left">77</td>
<td style="text-align:left">令狐冲</td>
<td style="text-align:left">英语</td>
<td style="text-align:left">文</td>
<td style="text-align:left">78.33</td>
<td style="text-align:left">-1.33</td>
</tr>
<tr>
<td style="text-align:left">8e0490684601</td>
<td style="text-align:left">66</td>
<td style="text-align:left">乔峰</td>
<td style="text-align:left">语文</td>
<td style="text-align:left">文</td>
<td style="text-align:left">75</td>
<td style="text-align:left">-9</td>
</tr>
<tr>
<td style="text-align:left">981222c9aa8e</td>
<td style="text-align:left">78</td>
<td style="text-align:left">张无忌</td>
<td style="text-align:left">语文</td>
<td style="text-align:left">文</td>
<td style="text-align:left">75</td>
<td style="text-align:left">3</td>
</tr>
<tr>
<td style="text-align:left">a841d6175683</td>
<td style="text-align:left">83</td>
<td style="text-align:left">令狐冲</td>
<td style="text-align:left">物理</td>
<td style="text-align:left">理</td>
<td style="text-align:left">79.67</td>
<td style="text-align:left">3.33</td>
</tr>
<tr>
<td style="text-align:left">b7e321377c21</td>
<td style="text-align:left">73</td>
<td style="text-align:left">张无忌</td>
<td style="text-align:left">数学</td>
<td style="text-align:left">理</td>
<td style="text-align:left">78.33</td>
<td style="text-align:left">-5.33</td>
</tr>
</tbody>
</table>
<p>传统做法：</p>
<pre><code class="language-sql">select score.*, avg as 该课平均, round(i_score - avg, 2) 成绩差
from score
         left join (
    select round(avg(i_score), 2) as avg, v_course
    from score
    group by v_course
) as a on a.v_course = score.v_course
order by score.id;
</code></pre>
<p>进阶做法：</p>
<pre><code class="language-sql">with cte as (
    select round(avg(i_score), 2) as avg, v_course
    from score
    group by v_course)

select score.*,avg as 该课平均, round(i_score - avg, 2) 成绩差
from score
         left join cte on cte.v_course = score.v_course
order by score.id;
</code></pre>
<p><code>PostgreSQL</code>中究极做法：</p>
<pre><code class="language-sql">select *,
       round(avg(i_score) over (PARTITION BY v_course), 2) as 该课平均,
       round(i_score - avg(i_score) over (PARTITION BY v_course), 2) as 成绩差
from score
order by score.id;
</code></pre>
<p>怎么样，如果你惊叹于<code>SQL</code>的强大，但是对此还不太了解的话，可以搜一下<code>窗口函数</code>。主流的商用数据库都是支持的，<code>PostgreSQL</code>作为一款开源免费的数据库，对于窗口函数的支持也是第一梯队的。</p>
<h4 id="4">需求4. 算出成绩单的合计值以及每个人的总成绩</h4>
<p>目标结果：</p>
<table>
<thead>
<tr>
<th style="text-align:left">v_name</th>
<th style="text-align:left">v_course</th>
<th style="text-align:left">sum</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">合计</td>
<td style="text-align:left"></td>
<td style="text-align:left">934</td>
</tr>
<tr>
<td style="text-align:left">张无忌</td>
<td style="text-align:left">总分</td>
<td style="text-align:left">294</td>
</tr>
<tr>
<td style="text-align:left">张无忌</td>
<td style="text-align:left">语文</td>
<td style="text-align:left">78</td>
</tr>
<tr>
<td style="text-align:left">张无忌</td>
<td style="text-align:left">英语</td>
<td style="text-align:left">82</td>
</tr>
<tr>
<td style="text-align:left">张无忌</td>
<td style="text-align:left">物理</td>
<td style="text-align:left">61</td>
</tr>
<tr>
<td style="text-align:left">张无忌</td>
<td style="text-align:left">数学</td>
<td style="text-align:left">73</td>
</tr>
<tr>
<td style="text-align:left">令狐冲</td>
<td style="text-align:left">总分</td>
<td style="text-align:left">309</td>
</tr>
<tr>
<td style="text-align:left">令狐冲</td>
<td style="text-align:left">语文</td>
<td style="text-align:left">81</td>
</tr>
<tr>
<td style="text-align:left">令狐冲</td>
<td style="text-align:left">英语</td>
<td style="text-align:left">77</td>
</tr>
<tr>
<td style="text-align:left">令狐冲</td>
<td style="text-align:left">物理</td>
<td style="text-align:left">83</td>
</tr>
<tr>
<td style="text-align:left">令狐冲</td>
<td style="text-align:left">数学</td>
<td style="text-align:left">68</td>
</tr>
<tr>
<td style="text-align:left">乔峰</td>
<td style="text-align:left">总分</td>
<td style="text-align:left">331</td>
</tr>
<tr>
<td style="text-align:left">乔峰</td>
<td style="text-align:left">语文</td>
<td style="text-align:left">66</td>
</tr>
<tr>
<td style="text-align:left">乔峰</td>
<td style="text-align:left">英语</td>
<td style="text-align:left">76</td>
</tr>
<tr>
<td style="text-align:left">乔峰</td>
<td style="text-align:left">物理</td>
<td style="text-align:left">95</td>
</tr>
<tr>
<td style="text-align:left">乔峰</td>
<td style="text-align:left">数学</td>
<td style="text-align:left">94</td>
</tr>
</tbody>
</table>
<p>说实话，对于这种需求，不给我一个高级语言的话，真的是有点为难我了。好在我们有<code>PostgreSQL</code>，做起来并没有你想象中的难。</p>
<pre><code class="language-sql">SELECT
    CASE WHEN GROUPING(v_name) = 1
             THEN '合计'
         ELSE v_name END,
    CASE WHEN  GROUPING(v_name) &lt;&gt; 1 and GROUPING(v_course) = 1
             THEN '总分'
         ELSE v_course END,
    sum(i_score)
FROM score
GROUP BY ROLLUP (v_name, v_course)
ORDER BY GROUPING(v_name) DESC ,v_name DESC, GROUPING(v_course) DESC ,v_course DESC;
</code></pre>
<p>很神奇是不是？寥寥数语就解决了需要高级语言编写逻辑代码才能搞定的问题。</p>
<h4 id="">总结</h4>
<p><code>SQL</code>是一门古老而强大的技艺，我一直觉得<code>SQL</code>的优雅是一种介于技术与艺术之间的美。在本文中，我以<code>PostgreSQL</code>为例展示了一些实用的<code>SQL</code>用法，本质上说，这些用法都是存在于<code>SQL标准</code>中的，而并非<code>PostgreSQL</code>独有，但不可否认，<code>PostgreSQL</code>作为一款开源免费的产品，能提供如此优秀的<strong>标准</strong>支持，是社区为全世界开发者提供的宝贵财富。</p>
<p>很多开发人员，他们的日常工作常常陷在无边的业务堆叠之中，每日都是在做<strong>增删改查</strong>。我听到过不止一次，大家对<strong>增删改查</strong>的厌倦、厌恶，甚至是彻头彻尾的鄙视。但是请不要忘记两点：</p>
<ol>
<li><code>SQL</code>是绝大多数软件系统运转的基石，在这个世界上任何被称作<code>基石</code>的东西，都不可以被轻视，谁轻视它，谁就要栽跟头。</li>
<li>“世事洞明皆学问”，<strong>增删改查</strong>一样可以彰显技术实力。同样是搬砖，优秀的人，总有优秀的解决方案。</li>
</ol>
<p>相信今天你已经初步体会到了<code>PostgreSQL</code>与<code>SQL</code>之美，在下一期中，我会展示真正属于<code>PostgreSQL</code>的独门绝技，带你领略更绚丽的风景，我们下期再见。</p>
<!--kg-card-end: markdown--><p><strong>推荐阅读本系列的其他文章：</strong></p><ul><li><a href="https://chinese.freecodecamp.org/news/2021-postgres-1/">2021年了，你真的应该考虑PostgreSQL了（1）</a></li><li><a href="https://chinese.freecodecamp.org/news/2021-postgres-3/">2021年了，你真的应该考虑PostgreSQL了（3）</a></li><li><a href="https://chinese.freecodecamp.org/news/2021-postgres-4/">2021年了，你真的应该考虑PostgreSQL了（4·终章）</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 2021年了，你真的应该考虑PostgreSQL了（1） ]]>
                </title>
                <description>
                    <![CDATA[ 最近几年，我已经帮助几个团队把他们的主力关系型数据库从其他xxSQL切换到PostgreSQL（以下简称PG）。可以这么说，用过PG 的小伙伴们，几乎都不愿意换回之前的关系型数据库了。那么PG到底有什么魔力，能得到大家的一致好评？我会通过一系列文章，好好介绍一下这款备受好评的明星级产品。 本篇是这个系列的第一篇，着重讲讲PG的背景知识和国际、国内的应用地位。如果你的团队或者项目还没有使用过PG，希望这篇文章能消除你的顾虑，大胆在项目中尝试一下， PG一定不会让你失望。 > The World's Most Advanced Open Source Relational Database 这是PG官网对自己的介绍，是的，你没有看错，“世界上最先进的开源关系型数据库”。一段严重违反我国广告法的话，上一个敢那么叫嚣的技术是PHP ，“世界上最好的语言”，然后这句话就成了码农界最广为人知的梗，存在于各种笑料中。不过PG 并没有因为这样明目张胆地自吹自擂而遭到什么抨击或调侃，事实上，无论在务实的码农界，抑或是讲究章法的学术界，人们对PG都是赞许有加，PG是完全当得起这句话的。 感兴趣的小伙 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/2021-postgres-1/</link>
                <guid isPermaLink="false">5fc9d30d39641a0517d5199e</guid>
                
                    <category>
                        <![CDATA[ PostgreSQL ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 牧云踏歌 ]]>
                </dc:creator>
                <pubDate>Fri, 04 Dec 2020 08:11:17 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2020/12/iShot2020-12-04-14.24.51.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>最近几年，我已经帮助几个团队把他们的主力关系型数据库从其他<code>xxSQL</code>切换到<code>PostgreSQL</code>（以下简称<code>PG</code>）。可以这么说，用过<code>PG</code>的小伙伴们，几乎都不愿意换回之前的关系型数据库了。那么<code>PG</code>到底有什么魔力，能得到大家的一致好评？我会通过一系列文章，好好介绍一下这款备受好评的明星级产品。</p><p>本篇是这个系列的第一篇，着重讲讲<code>PG</code>的<strong><strong>背景知识和国际、国内的应用地位</strong></strong>。如果你的团队或者项目还没有使用过PG，希望这篇文章能消除你的顾虑，大胆在项目中尝试一下，<code>PG</code>一定不会让你失望。</p><blockquote>The World's Most Advanced Open Source Relational Database</blockquote><p>这是<code>PG</code>官网对自己的介绍，是的，你没有看错，“世界上最先进的开源关系型数据库”。一段严重违反我国广告法的话，上一个敢那么叫嚣的技术是<code>PHP</code>，“世界上最好的语言”，然后这句话就成了码农界最广为人知的梗，存在于各种笑料中。不过<code>PG</code>并没有因为这样明目张胆地自吹自擂而遭到什么抨击或调侃，事实上，无论在务实的码农界，抑或是讲究章法的学术界，人们对<code>PG</code>都是赞许有加，<code>PG</code>是完全当得起这句话的。</p><p><em>感兴趣的小伙伴现在也可以打开MySQL的官网，那里也有一句违反我国广告法的话。</em></p><p>在讨论<code>PG</code>的强大功能之前，我们先了解一下开源协议相关的背景知识。</p><p><code>Open≠Free</code>，<strong><strong>开源不等于免费</strong></strong>，这是个老生常谈的问题了，无奈有些公司还没有意识到。这里转一张老图：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image.png" class="kg-image" alt="image" width="600" height="400" loading="lazy"></figure><p>图中最令人闻风丧胆（非贬义）的协议就是<code>GPL</code>，一种传染协议，也就是要求你动了源码或者仅仅只是做了静态连接（Static Link）就必须也是用<code>GPL</code>协议开源出来。采用这个协议的典型代表就是<code>Linux 内核</code>，当年小米公司被国外开发大神硬怼，也就是受这个协议的影响，感兴趣的小伙伴可以搜搜<code>小米 GPL 指责</code>。关于开源协议的条条框框和经典案例足够出一本书了。这里大家知道一点就好，<code>GPL</code>是一种非商业友好协议，如果你要在商业项目上选择开源框架或者其他什么工具，一定要留意避开<code>GPL</code>以免带来不必要的麻烦。</p><p>为什么说这么多协议的事情呢？其实就是想提醒一下大家。目前业内使用量最多的开源数据库<code>MySQL</code>数据库，大家都是免费用的吧？而这个免费用的<code>MySQL</code>社区版，恰恰就是<code>GPL</code>协议的。这个在<a href="https://www.mysql.com/downloads/">官网</a>写得明明白白：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-1.png" class="kg-image" alt="image-1" width="600" height="400" loading="lazy"></figure><p>虽然说数据库这种东西，跟大家的软件项目是松耦合运行的。通常来说，我们编写的软件项目也不会被<code>MySQL</code>的<code>GPL</code>协议传染，但是随着数据库的使用深入，当<code>MySQL</code>的原始功能满足不了现有的场景，当你打算在<code>MySQL</code>的源码上动刀子的时候，情况就变得很微妙了。</p><p>还有一个问题这两年也日益凸显，就是说起我国因技术被卡脖子的事情，不管是政府还是民间，大家现在普遍对国外的技术，尤其是被美国技术寡头掌控的关键技术持有谨慎的态度。所以着眼未来的话，如果还选择由<code>Oracle</code>公司控制着的<code>MySQL</code>，我觉得是有一定风险的。</p><p>当我们回过头来看看<code>PG</code>，之前的顾虑都可以一扫而光。</p><p>首先<code>PG</code>的开源协议是一种类<code>BSD</code>的自有协议——<code>PostgreSQL License</code>，事实上早期的<code>PG</code>就是采用的<code>BSD</code>协议，后续换成自有协议并没有多少改变，依然属于最为友好的协议类型。不论是自用还是商用，都是完全没有问题，修改代码并且用来盈利也是毫无商业风险的。</p><p>其次，<code>PG</code>事实上不被任何一家公司所掌控，它背后的控制机构——<strong><strong>PostgreSQL全球开发小组</strong></strong>，是一个松散的组织。其核心成员来自全球各地的不同公司，如果你感兴趣，可以在<code>PG</code><a href="https://www.postgresql.org/community/contributors/">官网</a>查询到这个组织的成员列表。可以这么说，没有任何一个公司享有对<code>PG</code>的绝对控制权，<code>PG</code>永远是属于社区的。</p><p>那么是什么造就了今天的<code>PG</code>呢，咱们稍微回顾一下历史，感受一下开源的力量。<code>PG</code>源于<code>UC Berkeley</code>大学1977年的<code>Ingress</code>计划，这个项目由<code>Michael Stonebraker</code>领导。平平无奇的一句话，透露出三个信息：</p><ol><li><code>1977</code>，相当有年头的事情了，估计此刻正在阅读本文的你，在那时还未呱呱坠地😃。</li><li><code>UC Berkeley</code>，可以搜一下，世界最知名的7所大学之一，美国最好的公立大学。</li><li><code>Michael Stonebraker</code>，2015年图灵奖获得者，绝对的大佬。</li></ol><p>用咱们中国老话说，<strong><strong>天时、地利、人和</strong></strong>正好应对以上三条。可见<code>PG</code>一出生就不同凡响。</p><p>时间推移到1994年，<code>UC Berkeley</code>大学两个研究生<code>Andrew Yu</code>、<code>Jolly Chen</code>给<code>PG</code>增加了SQL语言解释器，建立了<code>Postgres95</code>，随后的1996年，正式重命名为<code>PostgreSQL</code>，从此开启了<code>PG</code>辉煌的二十余年。</p><p>仔细留意一下上面两个研究生的名字，是不是看着很亲切？我特意搜了下这俩哥们的照片，放出来给大家看看：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-2.png" class="kg-image" alt="截屏2020-12-03 下午4.18.48" width="600" height="400" loading="lazy"></figure><p>看了照片感觉更亲切，这俩兄弟是哪国人，不言自明了吧：）</p><p>往后的事，有意思也很多，但是限于篇幅，咱们不能一直扯。这里就讲一点，估计也是大家最为关心的一点，<strong><strong>既然<code>PG</code>历史这么悠久，如果它真的如宣传所说，这么强的话，为什么现在大家都在用<code>MySQL</code>而不是<code>PG</code>呢？</strong></strong></p><p>说实话，这个问题，同样困扰了我很久，我也向一些前辈请教过，至今也没有权威的答案。这里就谈谈我自己的思路，两个原因：</p><ol><li><code>PG</code>支持<code>Windows</code>太晚了。有多晚呢？直到<code>2005</code>年，才原生支持<code>Windows</code>，<code>2005</code>年啊，比<code>PG</code>支持<code>SQL</code>晚了十年，比互联网在中国兴起、繁荣、泡沫戳破也晚了好几年。想想最重要的<code>2000</code>年前后，多少懵懂的站长都在使用<code>Windows</code>，<code>PG</code>错过了<code>Windows</code>就错过了最重要的一批在互联网上尝到甜头的人，从此一步错步步错（这个“错”不是“错误”的意思，而是“错过”的意思）。</li><li><code>LAMP</code>的崛起，继续将<code>PG</code>边缘化。现在很少有人提<code>LAMP</code>这个缩写了，最早它是<code>Linux/Apache/MySQL/PHP</code>的意思。我第一次听到这个缩写是08年，那年我还在读大二。可以想象一下这个缩写有多火，连一个大二的学生都听过，而且那年我还无数次的给同学们安利这套技术，因为它看起来真的很时髦。而直到我参加工作的几年后，才第一次听说<code>PG</code>，等在项目中正式使用<code>PG</code>，已是<code>2015</code>年之后的事了。（一不小心，又是十年）</li></ol><p>时也，命也，怎不令人唏嘘？</p><p>扯远了，让我们说回现在。</p><p>最近两年数据库国产化的呼声也很高。应该说咱们也取得了一些成果，比如华为的<a href="https://opengauss.org/zh/">openGauss</a>，腾讯的<a href="https://tbase.qq.com/">Tbase</a>，老牌的<a href="http://www.dameng.com/">达梦</a>，风头正盛的<a href="https://pingcap.com/">TiDB</a>，阿里的<a href="https://www.oceanbase.com/">OceanBase</a>，还有百度的<a href="https://github.com/baidu/BaikalDB">BaikalDB</a>等等等等，可谓是百花齐放。</p><p>这里咱单说前面那哥俩，华为的<a href="https://opengauss.org/zh/">openGuauss</a>，腾讯的<a href="https://tbase.qq.com/">Tbase</a>都是跟<code>PG</code>颇有渊源的数据库。如果你查看它们的官网，或许不会看到<code>Postgres</code>的字样，但是如果你去<code>GitHub</code>看看它们的源码及说明，就会发现离不开<code>PG</code>的影子，用大白话说，它俩都是在<code>PG</code>上衍生出来的。当然这也不是什么秘密，不重复造轮子乃是业界共识，事实上无论是华为还是腾讯，都在<code>PG</code>上做了不少工作，也为我国<code>PG</code>社区的繁荣出过很多力。</p><p>我举这个例子主要是想说明一个问题，<code>PG</code>的开源协议非常友好，你甚至可以把它拿来改头换面，说成是自己的数据库，也没有什么法律风险。</p><p>当然大部分小伙伴也就是把<code>PG</code>拿来用在项目上，我想你们肯定关心，都有哪些公司已经在使用<code>PG</code>了呢？这里我也准备了一张老图，几年前的了：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-3.png" class="kg-image" alt="image-3" width="600" height="400" loading="lazy"></figure><p>怎么样？还可以吧？可以看出<code>PG</code>在各行各业都扮演了重要的角色，这还是几年前的图。有些大公司也没给列出来，像中国移动、平安科技、摩拜单车、探探科技、苏宁云商，也都在使用<code>PG</code>哦。</p><p>有了这么多大公司对<code>PG</code>的认可，<code>PG</code>在整个数据库领域的热度也是与日俱增。这里有一张最近几年循环洗脑的图，估计大家也在各种场合见过：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-4.png" class="kg-image" alt="截屏2020-12-03 下午5.53.57" width="600" height="400" loading="lazy"></figure><p>可以看出<code>PG</code>在一众数据库中披荆斩棘，绝对是众多关系型数据库中最靓的仔😉。</p><p>当然<code>DB-Engines</code>的排名也不能太当回事，我觉得远不如直接做问卷调查更有说服力，只要样本够大就能说明一些问题。还好<code>Stack Overflow</code>作为世界上最大的开发者问答社区，在今年二月做了一份问卷调查，共收集到<strong><strong>65000</strong></strong>份样本，整理了一份非常有价值的<a href="https://insights.stackoverflow.com/survey/2020">报告</a>。如果你还没有看过，那我强烈建议你看一看。</p><p>现在我带大家简单看一下关于数据库方便的调查结果。首先是最受欢迎的数据库：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-5.png" class="kg-image" alt="image-5" width="600" height="400" loading="lazy"></figure><p>第一名是<code>Redis</code>，人见人爱的数据库，并不意外。紧随其后的就是咱们的<code>PG</code>了，并且与第一名的差距非常小，也就是说<code>PG</code>是最受欢迎的关系型数据，怎么样，这样的结果是不是有点猛呢？</p><p>还有一个统计数据也很能说明问题，就是受调查者正在使用的数据库的情况：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-6.png" class="kg-image" alt="image-6" width="600" height="400" loading="lazy"></figure><p>可以看到<code>PG</code>虽然落后<code>MySQL</code>一个身位，暂居第二，但是这已经比<code>DB-Engines</code>中的第四的排名提高了不少。可以这么理解，在活跃于社区的开发者中，采纳<code>PG</code>的比重还是比较高的，至少比<code>Oracle</code>高不少，即使跟<code>Microsoft Sql Server</code>比较也丝毫不逊色。</p><h4 id="-"><strong>总结</strong></h4><p>本篇是关于<code>PostgreSQL</code>系列中的第一篇。本文中用了不少笔墨介绍了<code>PG</code>的过去和现在，我想你应该对这门存在了几十年的技术有点兴趣了吧。下一篇，我会用更加技术流的方式介绍下<code>PG</code>到底牛在哪里，有什么让人大呼过瘾的特色。</p><p><code>PG</code>从不让人失望，我们下一篇再见。</p><p><strong>推荐阅读本系列的其他文章：</strong></p><ul><li><a href="https://chinese.freecodecamp.org/news/2021-postgres-2/">2021年了，你真的应该考虑PostgreSQL了（2）</a></li><li><a href="https://chinese.freecodecamp.org/news/2021-postgres-3/">2021年了，你真的应该考虑PostgreSQL了（3）</a></li><li><a href="https://chinese.freecodecamp.org/news/2021-postgres-4/">2021年了，你真的应该考虑PostgreSQL了（4·终章）</a></li></ul> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
