我刚刚开始使用 Postgres。阅读此文档时,我遇到了以下查询:
SELECT title, ts_rank_cd(textsearch, query) AS rank
FROM apod, to_tsquery('neutrino|(dark & matter)') query
WHERE query @@ textsearch
ORDER BY rank DESC
LIMIT 10;
Run Code Online (Sandbox Code Playgroud)
我可以理解这个查询中的所有内容,除了这个:FROM apod, ...
。
这,
是什么意思?我习惯于连接但不习惯于用FROM
逗号分隔的多个语句。
我在网上搜索无果。在查看并思考之后,在我看来,它声明了一个名为 query 的变量,因此它可以多次使用它。但如果这是真的,这与什么有关系FROM
?
Erw*_*ter 12
该手册对表格表达式一章中列表中的逗号进行了FROM
详细解释:
该
FROM
条款从以逗号分隔的表格参考列表中给出的一个或多个其他表格派生出一个表格。
FROM table_reference [, table_reference [, ...]]
表引用可以是表名(可能是模式限定的),也可以是派生表,例如子查询、
JOIN
构造或这些的复杂组合。如果FROM
子句中列出了多个表引用,则这些表是交叉连接的(即,它们的行的笛卡尔积形成;见下文)。
在 SQL 标准的早期版本中定义了逗号分隔的表引用而不是显式JOIN
语法这一事实不会使逗号错误或过时。在技术上需要的地方(见下文)或在使查询文本更清晰的地方使用显式连接语法。
又是说明书:
FROM T1 CROSS JOIN T2
相当于FROM T1 INNER JOIN T2 ON TRUE
(见下文)。它也等价于FROM T1, T2
。
在某些极端情况下,两者并不完全等效。手册:
注意
当出现两个以上的表时,后一种等价并不完全成立,因为JOIN
绑定比逗号更紧密。例如FROM T1 CROSS JOIN T2 INNER JOIN T3 ON condition
,这与FROM T1, T2 INNER JOIN T3 ON condition
因为第一种情况下的condition
can 引用T1
而不是第二种情况不同。
这个相关问题证明了差异的相关性:
基本上,您的观察完全正确:
在我看来,它声明了一个名为 query 的变量,因此它可以多次使用它。
任何函数都可以用作FROM
列表中的“表函数” 。并且函数参数可以引用函数左侧所有表中的列,因为符号:
FROM apod, to_tsquery('neutrino|(dark & matter)') query
Run Code Online (Sandbox Code Playgroud)
...实际上相当于:
FROM apod CROSS JOIN LATERAL to_tsquery('neutrino|(dark & matter)') AS query
Run Code Online (Sandbox Code Playgroud)
出现的表函数
FROM
也可以在关键字之前LATERAL
,但对于函数关键字是可选的;在任何情况下,函数的参数都可以包含对前面的 FROM 项提供的列的引用。
大胆强调我的。
该关键字AS
是完全之前可选噪声表别名(而不是列的别名,它不建议省略AS
,以避免可能的歧义)。看:
Eva*_*oll 11
它创建了一个隐式的CROSS JOIN
. 这是 SQL-89 语法。
在这里,我使用values(1)
和values(2)
创建伪表(值表)仅作为示例。他们之后的东西t(x)
,g(y)
被称为FROM-Aliases括号内的字符是列的别名(x
和y
分别)。您可以轻松地创建一个表来测试这一点。
SELECT *
FROM (values(1)) AS t(x), (values(2)) AS g(y)
Run Code Online (Sandbox Code Playgroud)
这就是你现在写的方式。
SELECT *
FROM (values(1)) AS t(x)
CROSS JOIN (values(2)) AS g(y);
Run Code Online (Sandbox Code Playgroud)
从那里,您可以INNER JOIN
通过添加条件使其成为隐式。
SELECT *
FROM (values(1)) AS t(x)
CROSS JOIN (values(1)) AS g(z)
WHERE x = z;
Run Code Online (Sandbox Code Playgroud)
或者显式和更新的INNER JOIN
语法,
SELECT *
FROM (values(1)) AS t(x)
INNER JOIN (values(1)) AS g(z)
ON ( x = z );
Run Code Online (Sandbox Code Playgroud)
所以在你的例子中..
FROM apod, to_tsquery('neutrino|(dark & matter)') query
Run Code Online (Sandbox Code Playgroud)
这与较新的语法基本相同,
FROM apod
CROSS JOIN to_tsquery('neutrino|(dark & matter)') AS query
Run Code Online (Sandbox Code Playgroud)
这实际上是相同的,在这种情况下,因为to_tsquery()
返回一行而不是一个集合,
SELECT title, ts_rank_cd(
textsearch,
to_tsquery('neutrino|(dark & matter)')
) AS rank
FROM apod
WHERE to_tsquery('neutrino|(dark & matter)') @@ textsearch
ORDER BY rank DESC
LIMIT 10;
Run Code Online (Sandbox Code Playgroud)
但是,上述情况可能会导致to_tsquery('neutrino|(dark & matter)')
发生两次,但在这种情况下,它不会 --to_tsquery
标记为STABLE(用 验证\dfS+ to_tsquery
)。
STABLE
表示该函数无法修改数据库,并且在单个表扫描中,对于相同的参数值,它将始终返回相同的结果,但其结果可能会在 SQL 语句之间发生变化。对于结果取决于数据库查找、参数变量(例如当前时区)等的函数,这是合适的选择。(对于希望查询由当前命令修改的行的 AFTER 触发器是不合适的。)另请注意, current_timestamp 系列函数被认为是稳定的,因为它们的值在事务中不会改变。
有关 SQL-89 和 SQL-92 之间差异的更完整比较,另请参阅我的回答here