PostgreSQL SQL 语言:类型转换

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: SQL语句可能(有意无意地)要求在同一表达式里混合不同的数据类型。 PostgreSQL在计算混合类型表达式方面有许多功能。 在大多数情况下,用户不需要明白类型转换机制的细节。但是,由PostgreSQL进行的隐式类型转换会对查询的结果产生影响。

本文档为PostgreSQL 9.6.0文档,本转载已得到原译者彭煜玮授权。

1. 概述

SQL是一种强类型语言。也就是说,每个数据项都有一个相关的数据类型,数据类型决定其行为和允许的用法。 PostgreSQL有一个可扩展的类型系统,该系统比其它SQL实现更具通用和灵活。因而,PostgreSQL中大多数类型转换行为是由通用规则来管理的,而不是ad hoc启发式规则。这种做法允许使用混合类型表达式,即便是其中包含用户定义的类型。

PostgreSQL扫描器/解析器只将词法元素分解成五个基本种类:整数、非整数数字、字符串、标识符、关键字。大多数非数字类型常量首先被分类为字符串。SQL语言定义允许将类型名指定为字符串, 这个机制被PostgreSQL用于保证解析器沿着正确的方向运行。例如,查询:

SELECT text 'Origin' AS "label", point '(0,0)' AS "value";

 label  | value
--------+-------
 Origin | (0,0)
(1 row)

有两个文字常量,类型分别为text和point。如果一个串文字没有指定类型,初始将被分配一个占位符类型unknown,该类型将在下文描述的后续阶段被解析。

在SQL解析器里,有四种基本的SQL结构要求独立的类型转换规则:

函数调用

PostgreSQL类型系统的大部分建立在一套丰富的函数上。 函数可以有一个或多个参数。由于PostgreSQL允许函数重载, 所以函数名自身并不唯一地标识将要被调用的函数,解析器必须根据提供的参数类型选择正确的函数。

操作符

PostgreSQL允许带有前缀和后缀一元(单目)操作符的表达式,也允许二元(两个参数)操作符。像函数一样,操作符也可以被重载,因此操作符的选择也有同样的问题。

值存储

SQL INSERT和UPDATE语句将表达式的结果放 入表中。语句中的表达式类型必须和目标列的类型一致(或者可以被转换为一致)。

UNION、CASE和相关结构

因为来自一个联合的SELECT语句中的所有查询结果必须在一个列集中显示,所以每个 SELECT子句的结果类型必须能相互匹配并被转换成一个统一的集合。类似地,一个 CASE结构的结果表达式必须被转换成一种公共的类型,这样CASE表达式作为整体才 有一种已知的输出类型。同样的要求也存在于ARRAY结构以及GREATEST和LEAST函数中。

系统目录存储有关哪些数据类型之间存在哪种转换(或造型)以及如何执行这些转换的相关信息。额外的造型可以由用户通过CREATE CAST命令增加(这个通常和定义一种新的数据类型一起完成。 内建的类型转换集已经经过了仔细的雕琢,最好不要去更改它们)。

解析器提供了一种额外的启发式规则,它允许在具有隐式造型的类型组中恰当造型行为的改进决定。 数据类型被分为几个基本的类型分类,包括boolean、numeric、string、bitstring、datetime、timespan、geometric、network和用户自定义(可参阅Table 50-56中的列表;但需要注意的是 也可以创建自定义的类型分类)。在每个分类中,可以有一个或多个首选类型, 当存在类型选择时,这个是更好的选择。利用精心选择的首选类型和可用的隐式造型, 我们可以确保有歧义的表达式(那些有多个候选解析方案的表达式)可以用一种有用的方式来处理。

所有类型转换规则都是建立在下面几个基本原则上的:

  • 隐式转换决不能有意外的或不可预见的输出。
  • 如果一个查询不需要隐式类型转换,解析器或执行器不应该有额外的开销。也就是说,如果一个查询是结构良好的并且类型已经匹配,则查询不应该在解析器里耗费额外的时间执行,也不会在查询中引入不必要的隐式类型转换调用。
  • 另外,如果一个查询通常要求为某个函数进行隐式类型转换,而用户定义了一个有正确参数类型的新函数, 解析器应该使用新函数并不再做隐式转换来使用旧函数。

2. 操作符

被一个操作符表达式引用的特定操作符由下列过程决定。注意这个过程会被所涉及的操作符的优先级间接地影响,因为这将决定哪些子表达式被用作哪个操作符的输入。详见Section 4.1.6。

操作符类型决定

1.从系统目录pg_operator中选出要考虑的操作符。如果使用了一个不带模式限定的操作符 名(常见的情况),那么操作符被认为是那些在当前搜索路径中可见并有匹配的名字和参数个数的操作符。如果给出一个被限定的操作符名,那么只考虑指定模式中的操作符。

a.如果搜索路径找到了多个有相同参数类型的操作符,那么只考虑最早出现在路径中的那一个。 但是不同参数类型的操作符将被平等看待,而不管它们在路径中的位置如何。

2.查找一个正好接受输入参数类型的操作符。如果找到一个(在一组被考虑的操作符中,可能只存在一个正好匹配的),则使用之。

a.如果一个二元操作符调用中的一个参数是unknown类型,则在本次检查中假设它与另一个参数类型相同。 对于涉及两个unknown输入的调用或者带有一个unknown输入的一元操作符,在这一步将永远找不到一个匹配。

b.如果一个二元操作符调用的其中一个参数是unknown类型 而另一个是一种域类型,下一次检查会看看是否有一个操作符正好在两边都 接受该域的基类型,如果有就使用它。

3.寻找最优匹配。

a.抛弃那些输入类型不匹配并且也不能被转换成匹配的候选操作符。 unknown文字被假定为可以为这个目的被转换为 任何东西。如果只剩下一个候选操作符,则使用之,否则继续下一 步。

b.如果任何输入参数是一种域类型,对所有后续步骤都把它当做是该 域的基类型。这确保在做有歧义的操作符解析时,域的举止像它们 的基类型。

c.遍历所有候选操作符,保留那些在输入类型上的匹配最准确的。如果没有一个操作符能准确匹配,则保留所有候选。如果只剩下一个候选操作符,则使用之,否则继续下一步。

d.遍历所有候选操作符,保留那些在最多个需要类型转换的位置上接受首选类型(属于输入数据类型的类型分类)的操作符。如果没有接受首选类型的操作符,则保留所有候选。如果只剩下一个候选操作符,则使用之, 否则继续下一步。

e.如果有任何输入参数是unknown类型,检查被剩余候选操作符在那些参数位置上接受的类型分类。 在每一个位置,如果任何候选接受该分类,则选择string分类(这种对字符串的偏爱是合适的, 因为未知类型的文本确实像字符串)。否则,如果所有剩下的候选操作符都接受相同的类型 分类,则选择该分类;否则抛出一个错误(因为在没有更多线索的条件下无法作出正确 的推断)。现在抛弃不接受选定的类型分类的候选操作符。然后,如果任意候选操作符接受那个分类中的首选类型, 则抛弃那些在该参数位置接受非首选类型的候选操作符。如果没有候选操作符能通过这些测试则保留全部候选者。如果只剩下一个候选者,则使用之;否则继续下一步。

f.如果既有unknown参数也有已知类型的参数,并且所有已知类型参数具有相同的类型,则假定该unknown参数也是那种类型的,并且检查哪些候选操作符可以在该unknown参数的位置上接受那个类型。如果正好有一个候选者通过了这个测试,则使用之;否则失败。

下面是一些例子。

Example 10-1. 阶乘操作符类型决定

在标准目录中只有一个被定义的阶乘操作符(后缀!),它接受一个类型为bigint的参数。在下面这个查询表达式中,扫描器会为该参数分配一个初始类型integer:


SELECT 40 ! AS "40 factorial";

                   40 factorial
--------------------------------------------------
 815915283247897734345611269596115894272000000000
(1 row)

因此,解析器在操作数上做了一个类型转换,该查询等价于:


SELECT CAST(40 AS bigint) ! AS "40 factorial";

Example 10-2. 字符串连接操作符类型决定

一个类字符串的语法被用来处理字符串类型和处理复杂的扩展类型。未指定类型的字符串与可能的候选操作符匹配。

一个未指定参数的例子:


SELECT text 'abc' || 'def' AS "text and unknown";

 text and unknown
------------------
 abcdef
(1 row)

在这种情况下,解析器查看是否有一个操作符的两个参数都使用text。既然有,那么它假设第二个参数应被解释为text类型。

下面是两个未指定类型的值的连接:


SELECT 'abc' || 'def' AS "unspecified";

 unspecified
-------------
 abcdef
(1 row)

在这种情况下,没有对于使用哪种类型的初始提示,因为在查询中没有指定类型。 因此,解析器查找所有的候选操作符并找到候选者同时接受字符串分类和位串分类的输入。 因为字符串分类在可用时是首选的,该分类会被选中,并且接下来字符串的首选类型(text)会被用作解决未知类型文字的指定类型。

Example 10-3. 绝对值与否定操作符类型决定

PostgreSQL操作符目录中有几个对于前缀操作符@的条目, 这些都现实了针对各种数字数据类型的绝对值操作。其中之一用于float8类型,它是在数字分类中的首选类型。 因此,PostgreSQL将在遇到一个unknown输入时使用它:


SELECT @ '-4.5' AS "abs";
 abs
-----
 4.5
(1 row)
在这里,系统

SELECT @ '-4.5e500' AS "abs";

ERROR:  "-4.5e500" is out of range for type double precision

另一方面,前缀符~(按位取反)只为整数数据类型定义,而没有为float8定义。因此,如果我们尝试一个与使用~类似的情况,我们会得到:


SELECT ~ '20' AS "negation";

ERROR:  operator is not unique: ~ "unknown"
HINT:  Could not choose a best candidate operator. You might need to add
explicit type casts.

这是因为系统不能决定在几个可能的~符号中应该选择哪一个。我们可以用一个显式造型来帮助它:


SELECT ~ CAST('20' AS int8) AS "negation";

 negation
----------
      -21
(1 row)

Example 10-4. 数组包含操作符类型决定

这里是另一个决定带有一个已知和一个未知输入的操作符的例子:


SELECT array[1,2] <@ '{1,2,3}' as "is subset";

 is subset
-----------
 t
(1 row)

PostgreSQL操作符目录有一些条目用于中缀操作符<@,但是仅有的两个可以在左手边接受一个整数数组的是数组包含(anyarray <@ anyarray)和范围包含(anyelement <@ anyrange)。因为这些多态伪类型(见Section 8.20)中没有一个被认为是首选的,解析器不能以此为基础来解决歧义。不过,step 3.f告诉它假定位置类型的文字和其他输入的类型相同,即整数数组。现在这两个操作符中只有一个可以匹配,因此数组包含被选择(如果选择范围包含,我们将得到一个错误,因为该字符串没有成为一个范围文字的正确格式)。

Example 10-5. 域类型上的自定义操作符

用户有时会尝试声明只适用于一种域类型的操作符。这是可能的, 但是远非它看起来那么有用,因为操作符解析规则被设计为选择 适用于域的基类型的操作符。考虑这个例子:


CREATE DOMAIN mytext AS text CHECK(...);
CREATE FUNCTION mytext_eq_text (mytext, text) RETURNS boolean AS ...;
CREATE OPERATOR = (procedure=mytext_eq_text, leftarg=mytext, rightarg=text);
CREATE TABLE mytable (val mytext);

SELECT * FROM mytable WHERE val = 'foo';

这个查询将不会使用自定义操作符。解析器将首先看看是否有一个 mytext = mytext操作符( step 2.a),当然这里没有; 然后它将会考虑该域的基类型text,并且看看是否有一 个text = text操作符( step 2.b),这里也没有;因 此它会把unknown-类型文字解析为text 并使用text = text操作符。 让自定义操作符能被使用的唯一方法是显式地转换改文字:


SELECT * FROM mytable WHERE val = text 'foo';

这样根据准确匹配规则会立即找到 mytext = text操作符。如果 到达最佳匹配规则,它们会积极地排斥域类型上的操作符。如果它 们没有,这样一个操作符将创建太多歧义操作符失败,因为转换规 则总是认为一个域可以和它的基类型相互转换,并且因此该域操作 符在所有与该基类型上的一个类似命名的操作符相同的情况中都被 认为可用。

3. 函数

被一个函数调用引用的特定函数使用下面的过程来决定。

函数类型决定

1.从pg_proc系统目录中选择要被考虑的函数。 如果使用一个非模式限定的函数名称,那么函数被认为是那些在当前搜索路径中可见并有匹配的名字和参数个数的函数(参见Section 5.8.3)。如果给出一个被限定的函数名,那么只考虑指定模式中的函数。

a.如果搜索路径发现多个参数类型相同的函数,那么只考虑最早在搜索路径中出现的那个。 不同参数类型的函数被平等对待,不受在搜索路径中位置的影响。

b.如果使用一个VARIADIC数组参数声明一个函数,并且调用不使用关键字VARIADIC, 那么该函数就好像其数组参数被它的元素类型的一次或多次出现所替换,根据需要去匹配调用。 这样的扩展之后,函数可能会有和非可变函数相同的参数类型。在这种情况下,在搜索路径中出现比较早的函数将被使用,或者如果两个函数在相同的模式中时首选非可变的那一个。

c.考虑使用有默认参数值的函数来匹配任何省略了零个或者多个可默认参数位置的调用。如果有超出一个的这种函数匹配一个调用,那么使用最早出现在搜索路径中的那个。如果同一个模式中在同一个非默认位置上有两个或者更多这样的函数(如果它们有 不同的默认参数设置,这是可能的),系统将不能确定去选择哪一个,并且如果不能找到该调用更好的匹配,将会导致一个"有歧义的函数调用" 错误。

2.检查一个函数正好接受输入参数类型。如果存在一个(在所考虑的一组函数中只能有一个准确匹配),则使用之(在该步骤中,涉及unknown的情况将永远找不到一个匹配)。

3.如果没有发现准确匹配,那么查看函数调用是否作为一个特定的类型转换请求出现。 如果函数调用仅有一个参数并且函数名和一些数据类型的(内部)名称相同,那么该情况将会发生。 并且,该函数参数必须是一个未知类型的文字,或者是一个可以被二进制强制转换到命名数据类型的类型, 或者是一个可以通过应用其I/O函数被转换为命名数据类型的类型(也就是,转换是转到标准字符串类型或者从标准字符串类型转来)。当满足这些条件的时候,函数调用被当做CAST声明的一种形式来对待。 [1]

4.查找最佳匹配。

a.如果候选函数的输入类型不匹配并且不能通过转换(使用一个隐式转换)达到匹配,则丢弃它。为了这个目的,unknown文字被假定可被转换成任何东西。如果仅有一个候选项,则使用之;否则继续下一步。

b.如果任何输入参数是一种域类型,在所有后续步骤中都把它当做 该域的基类型。这确保在做有歧义的操作符解析时,域的举止像它们 的基类型。

c.遍历所有候选函数并保留那些最匹配输入类型的。如果没有准确匹配,则保留所有候选项。 如果仅有一个候选项,则使用之;否则继续下一步。

d.遍历所有候选函数并保留那些在最多要求类型转换的位置上接受首选类型(属于输入数据类型的类型分类)的候选项。如果没有接受首选类型的候选项,则保留所有候选项。如果仅有一个候选项,则使用之;否则继续下一步。

e.如果任何输入参数是unknown,那么检查那些被剩余候选项在那些参数位置上接受的类型分类。在每一个位置上,如果任何候选项接受该分类则选择string分类 (这个偏向于字符串是恰当的,因为一个未知类型文字看起来像字符)。 否则,如果所有剩余的候选项接受相同的类型分类,那么选择那个分类; 否则将失败,因为缺乏更多线索来推断出正确的选择。现在,丢弃不接受被选中类型分类的候选项。此外,如果任何候选项接受那个分类中的一个首选类型,则丢弃对该参数接受非首选类型的候选项。如果没有候选项能通过这些测试,则保留所有候选项。如果只剩下一个候选项,则使用之;否则继续下一步。

f.如果既有unknown参数也有已知类型的参数,并且所有已知类型参数具有相同的类型,则假定该unknown参数也是那种类型的,并且检查哪些候选函数可以在该unknown参数的位置上接受那个类型。如果正好有一个候选者通过了这个测试,则使用之;否则失败。

注意,对于操作符和函数类型决定来说"最优匹配"规则是完全相同的。下面是一些例子。

Example 10-6. 圆整函数参数类型决定

只有一个带有两个参数的圆整函数; 它采用第一个参数类型为numeric和第二个参数类型为integer。这样下面的查询自动将第一个类型为integer参数转换为numeric:


SELECT round(4, 4);

 round
--------
 4.0000
(1 row)

该查询实际上被解析器转换为:


SELECT round(CAST (4 AS numeric), 4);

因为包含小数点的数字常数初始会被分配类型numeric,下面的查询将不需要类型转换并因此可能会稍稍高效一些:


SELECT round(4.0, 4);

Example 10-7. 子串函数类型决定

有几个substr函数,其中一个用于text和integer类型。如果使用一个未指定类型的字符常量调用,那么系统选择接受一个首选分类string(也就是text类型)的参数的候选函数。


SELECT substr('1234', 3);

 substr
--------
     34
(1 row)

如果字符串被声明为类型varchar(如果它来自于一个表就会这样),那么解析器将尝试转换它为text:


SELECT substr(varchar '1234', 3);

 substr
--------
     34
(1 row)

解析器所作的转换:


SELECT substr(CAST (varchar '1234' AS text), 3);

Note:
解析器从pg_cast目录中知道text和varchar是二进制可兼容的, 意思是其中一个可以被传递给接受另一种类型的函数而不需要做任何物理转换。因此,在这种情况下不会真正使用类型转换调用。

并且,如果该函数使用一个integer类型的参数调用,那么解析器将尝试将它转换为text:


SELECT substr(1234, 3);
ERROR:  function substr(integer, integer) does not exist
HINT:  No function matches the given name and argument types. You might need
to add explicit type casts.

由于integer类型没有到text的一个隐式造型,这将不会工作。但是一次显式造型则可以工作:


SELECT substr(CAST (1234 AS text), 3);

 substr
--------
     34
(1 row)

Notes

[1]
这一步的原因是在没有一个实际的造型函数的情况下支持函数风格的造型声明。如果有一个造型函数,它被按惯例以其输出类型命名,并且不需要有特殊情况。

4. 值存储

将被插入到一个表的值会按照下列步骤被转换到目标列的数据类型。

值存储类型转换

1.检查一个与目标的准确匹配。

2.否则,尝试转换表达式为目标类型。如果在两种类型之间的一个 赋值造型已经被注册在pg_cast 目录(见CREATE CAST)中, 这是可能的。或者,如果该表达式是一个未知类型的文字, 则该文字串的内容将被提供给目标类型的输入转换例程。

3.检查是否有一个用于目标类型的尺寸调整造型。尺寸调整造型是一个从该类型到其自身的造型。 如果在pg_cast目录中找到一个,那么把表达式存储到目标列中之前把它应用到表达式。这样一个造型的实现函数总是采用一个额外的integer类型的参数,它接收目标列的atttypmod值(通常是它被声明的长度,尽管对于不同数据类型atttypmod有不同的解释),并且它可能采用第三个boolean参数来说明造型是显式的还是隐式的。该造型函数负责应用任何长度相关的语义,例如尺寸检查或截断。

Example 10-8. character存储类型转换

对于一个声明为character(20)的目标列,下面的语句展示了被存储的值如何被正确地调整尺寸:


CREATE TABLE vv (v character(20));
INSERT INTO vv SELECT 'abc' || 'def';
SELECT v, octet_length(v) FROM vv;

          v           | octet_length
----------------------+--------------
 abcdef               |           20
(1 row)

实际发生的事情是两个未知文字被默认决定为text,允许||操作符被决定为text连接。 然后操作符的text结果被转换成bpchar("blank-padded char"空白填充字符,character数据类型的内部名称)来匹配目标列类型(由于从text到bpchar的转换是二进制强制的,这个转换不会插入任何实际的函数调用)。最后,尺寸调整函数bpchar(bpchar, integer, boolean)被从系统目录中找到并应用到操作符的结果和存储的列长度上。这个类型相关的函数执行必要的长度检查并增加填充的空间。

5. UNION、CASE和相关结构

SQL UNION结构必须使可能不相似的类型匹配成为一个单一的结果集。该决定算法被独立地应用到一个联合查询的每个输出列。 INTERSECT和EXCEPT采用和UNION相同的方法来决定不相似的类型。CASE、ARRAY、VALUES、GREATEST和LEAST结构使用相同的算法来使它们的组成表达式匹配并选择一种结果数据类型。

UNION、CASE和相关结构的类型决定

  1. 如果所有的输入为相同类型,并且不是unknown,那么就决定是该类型。
  2. 如果任何输入是一种域类型,在所有后续步骤中都把它当做 该域的基类型。 [1]
  3. 如果所有的输入为unknown类型,则决定为text(字符串分类的首选类型)类型。否则,unknown输入被忽略。
  4. 如果非未知输入不全是相同的类型分类,则失败。
  5. 如果有的话,选择第一个在其分类中作为首选类型的非未知输入类型。
  6. 否则,选择最后的非未知输入类型,它允许所有在前面的非未知输入被隐式地转换为它(总有这样的一种类型,因为至少在列表中的第一个类型必须满足这个条件)。
  7. 转换所有的输入为选定的类型。如果没有一个从给定输入到选定类型的转换将会失败。

下面是一些例子。

Example 10-9. 联合中未指定类型的类型决定


SELECT text 'a' AS "text" UNION SELECT 'b';

 text
------
 a
 b
(2 rows)

这里,未知类型文字'b'将被决定为类型text。

Example 10-10. 简单联合中的类型决定


SELECT 1.2 AS "numeric" UNION SELECT 1;

 numeric
---------
       1
     1.2
(2 rows)

文字1.2是numeric类型,且integer值1可以被隐式地造型为numeric,因此使用numeric类型。

Example 10-11. 可换位联合中的类型决定


SELECT 1 AS "real" UNION SELECT CAST('2.2' AS REAL);

 real
------
    1
  2.2
(2 rows)

这里,由于类型real被能被隐式地造型为integer,而integer可以被隐式地造型为real,联合结果类型被决定为real。

Notes

[1]
多少有些类似于对待用于操作符和函数的域输入的方式,这种行为允许 一种域类型能通过一个UNION或相似的结构保留下来, 只要用户小心地确保所有的输入都是(显式地或隐式地)准确类型。否 则会优先选择该域的基类型。

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
16天前
|
关系型数据库 Go 网络安全
go语言中PostgreSQL驱动安装
【11月更文挑战第2天】
51 5
|
3月前
|
SQL 关系型数据库 MySQL
在MySQL中,什么是结构化查询语言 (SQL)
【8月更文挑战第20天】在MySQL中,什么是结构化查询语言 (SQL)
66 1
|
1月前
|
SQL Oracle 关系型数据库
SQL语言的主要标准及其应用技巧
SQL(Structured Query Language)是数据库领域的标准语言,广泛应用于各种数据库管理系统(DBMS)中,如MySQL、Oracle、SQL Server等
|
1月前
|
SQL 关系型数据库 MySQL
Go语言项目高效对接SQL数据库:实践技巧与方法
在Go语言项目中,与SQL数据库进行对接是一项基础且重要的任务
67 11
|
2月前
|
SQL 关系型数据库 C语言
PostgreSQL SQL扩展 ---- C语言函数(三)
可以用C(或者与C兼容,比如C++)语言编写用户自定义函数(User-defined functions)。这些函数被编译到动态可加载目标文件(也称为共享库)中并被守护进程加载到服务中。“C语言函数”与“内部函数”的区别就在于动态加载这个特性,二者的实际编码约定本质上是相同的(因此,标准的内部函数库为用户自定义C语言函数提供了丰富的示例代码)
|
3月前
|
SQL 存储 关系型数据库
PostgreSQL核心之SQL基础学习
PostgreSQL核心之SQL基础学习
47 3
|
3月前
|
SQL 关系型数据库 MySQL
|
3月前
|
SQL 存储 大数据
SQL 语言发展史简直太震撼啦!从诞生到现代数据处理,见证一场奇妙的演变之旅,快来感受!
【8月更文挑战第31天】SQL(结构化查询语言)自20世纪70年代由IBM研究员E.F. Codd提出以来,已成为现代数据处理不可或缺的一部分。它最初简化了层次和网状模型中复杂的存储与检索问题,通过基本的SELECT、FROM和WHERE关键字实现了数据查询。80年代,SQL在商业数据库中广泛应用,引入了GROUP BY、HAVING和ORDER BY等功能,增强了数据分析能力。90年代,互联网和企业信息化推动了SQL的进一步优化与扩展,支持分布式数据库和数据仓库等技术。
55 0
|
3月前
|
SQL 存储 NoSQL
从SQL到NoSQL:理解不同数据库类型的选择与应用——深入比较数据模型、扩展性、查询语言、一致性和适用场景,为数据存储提供全面决策指南
【8月更文挑战第31天】在信息技术飞速发展的今天,数据库的选择至关重要。传统的SQL数据库因其稳定的事务性和强大的查询能力被广泛应用,而NoSQL数据库则凭借其灵活性和水平扩展性受到关注。本文对比了两种数据库类型的特点,帮助开发者根据应用场景做出合理选择。SQL数据库遵循关系模型,适合处理结构化数据和复杂查询;NoSQL数据库支持多种数据模型,适用于非结构化或半结构化数据。SQL数据库在一致性方面表现优异,但扩展性较差;NoSQL数据库则设计之初便考虑了水平扩展性。SQL使用成熟的SQL语言,NoSQL的查询语言更为灵活。
80 0
|
3月前
|
SQL 数据可视化 数据挖掘
SQL 在数据分析中简直太牛啦!从数据提取到可视化,带你领略强大数据库语言的神奇魅力!
【8月更文挑战第31天】在数据驱动时代,SQL(Structured Query Language)作为强大的数据库查询语言,在数据分析中扮演着关键角色。它不仅能够高效准确地提取所需数据,还能通过丰富的函数和操作符对数据进行清洗与转换,确保其适用于进一步分析。借助 SQL 的聚合、分组及排序功能,用户可以从多角度深入分析数据,为企业决策提供有力支持。尽管 SQL 本身不支持数据可视化,但其查询结果可轻松导出至 Excel、Python、R 等工具中进行可视化处理,帮助用户更直观地理解数据。掌握 SQL 可显著提升数据分析效率,助力挖掘数据价值。
74 0
下一篇
无影云桌面