创建一个 PostgreSQL 函数,该函数成为 table 从其他 table 检索相关数据的公式字段

Create a PostgreSQL function that becomes a formula field of a table retrieving related data from other table

上面的例子可以在 SQL 服务器上完成。它是一个函数,在另一个 table 上执行计算,同时获取当前 table 字段 Id 以列出来自其他 table、return 单个值的数据。

问题:如何使用 Postgre 做正确的事情SQL


SELECT TOP(5) * FROM Artists;

+------------+------------------+--------------+-------------+
| ArtistId   | ArtistName       | ActiveFrom   | CountryId   |
|------------+------------------+--------------+-------------|
| 1          | Iron Maiden      | 1975-12-25   | 3           |
| 2          | AC/DC            | 1973-01-11   | 2           |
| 3          | Allan Holdsworth | 1969-01-01   | 3           |
| 4          | Buddy Rich       | 1919-01-01   | 6           |
| 5          | Devin Townsend   | 1993-01-01   | 8           |
+------------+------------------+--------------+-------------+


SELECT TOP(5) * FROM Albums;

+-----------+------------------------+---------------+------------+-----------+
| AlbumId   | AlbumName              | ReleaseDate   | ArtistId   | GenreId   |
|-----------+------------------------+---------------+------------+-----------|
| 1         | Powerslave             | 1984-09-03    | 1          | 1         |
| 2         | Powerage               | 1978-05-05    | 2          | 1         |
| 3         | Singing Down the Lane  | 1956-01-01    | 6          | 3         |
| 4         | Ziltoid the Omniscient | 2007-05-21    | 5          | 1         |
| 5         | Casualties of Cool     | 2014-05-14    | 5          | 1         |
+-----------+------------------------+---------------+------------+-----------+

函数

CREATE FUNCTION [dbo].[ufn_AlbumCount] (@ArtistId int)  
RETURNS smallint
AS  
BEGIN  
    DECLARE @AlbumCount int;
    SELECT @AlbumCount = COUNT(AlbumId)
    FROM Albums
    WHERE ArtistId = @ArtistId; 
    RETURN @AlbumCount;
END;
GO

现在,(在 SQL 服务器上)用 ALTER TABLE Artists ADD AlbumCount AS dbo.ufn_AlbumCount(ArtistId); 更新前 table 字段后,可以列出并得到以下结果。

+------------+------------------+--------------+-------------+--------------+
| ArtistId   | ArtistName       | ActiveFrom   | CountryId   | AlbumCount   |
|------------+------------------+--------------+-------------+--------------|
| 1          | Iron Maiden      | 1975-12-25   | 3           | 5            |
| 2          | AC/DC            | 1973-01-11   | 2           | 3            |
| 3          | Allan Holdsworth | 1969-01-01   | 3           | 2            |
| 4          | Buddy Rich       | 1919-01-01   | 6           | 1            |
| 5          | Devin Townsend   | 1993-01-01   | 8           | 3            |
| 6          | Jim Reeves       | 1948-01-01   | 6           | 1            |
| 7          | Tom Jones        | 1963-01-01   | 4           | 3            |
| 8          | Maroon 5         | 1994-01-01   | 6           | 0            |
| 9          | The Script       | 2001-01-01   | 5           | 1            |
| 10         | Lit              | 1988-06-26   | 6           | 0            |
+------------+------------------+--------------+-------------+--------------+

但是如何在 postgresql 上实现这个?

Postgres 不支持“虚拟”计算列(即在运行时生成的计算列),因此没有完全等效的列。最有效的解决方案是计算这个的视图:

create view artists_with_counts
as
select a.*, 
       coalesce(t.album_count, 0) as album_count
from artists a
  left join (
     select artist_id, count(*) as album_count
     from albums
     group by artist_id
  ) t on a.artist_id = t.artist_id;       

另一种选择是创建一个可用作 select 中的“虚拟列”的函数 - 但由于这是逐行完成的,因此这将比视图慢得多。

create function album_count(p_artist artists)
  returns bigint
as
$$
  select count(*)
  from albums a
  where a.artist_id = p_artist.artist_id;
$$
language sql
stable;

那么您可以将其作为一列包括在内:

select a.*, a.album_count
from artists a;

使用这样的函数,需要在函数引用前加上 table 别名(或者,您可以使用 album_count(a)

Online example