如何使用PL/pgSQL在Supabase中动态创建表和函数?

问题描述 投票:0回答:1

我正在努力在我的 Supabase 数据库中设置矢量存储,并且我需要为我创建的每个新表执行一个脚本。该脚本启用 pgvector 扩展,创建一个表,并定义一个函数来根据向量相似性搜索文档。

这是我需要执行的脚本:

-- Check if the extension exists
create extension if not exists vector;

-- Drop the function if it exists
drop function if exists match_documents(vector(1024), int, jsonb);

-- Create a table to store your documents
create table documents (
  id bigint primary key generated always as identity,
  content text, -- corresponds to Document.pageContent
  metadata jsonb, -- corresponds to Document.metadata
  embedding vector(1024) -- 1024 works for OpenAI embeddings, change if needed
);

-- Create a function to search for documents
create function match_documents (
  query_embedding vector(1024),
  match_count int default null,
  filter jsonb default '{}'
) returns table (
  id bigint,
  content text,
  metadata jsonb,
  similarity float
) language plpgsql as $$
#variable_conflict use_column
begin
  return query
  select
    id,
    content,
    metadata,
    1 - (documents.embedding <=> query_embedding) as similarity
  from documents
  where metadata @> filter
  order by documents.embedding <=> query_embedding
  limit match_count;
end;
$$;

问题是这个脚本总是创建一个名为文档的表。我想创建一个函数,将表名称作为输入并执行脚本,从而允许我动态创建具有不同名称的表。该函数将使用我的 Supabase Python SDK 中的远程 RPC 调用来调用。

这是我为实现此目的而编写的函数:

create or replace function setup_vector_store(table_name text)
returns void
language plpgsql
as $$
begin
  -- Enable the pgvector extension
  execute 'create extension if not exists vector';

  -- Drop the function if it exists
  execute 'drop function if exists match_documents(vector(1024), int, jsonb)';

  -- Create the table
  execute format('
  create table %I (
    id bigint primary key generated always as identity,
    content text,
    metadata jsonb,
    embedding vector(1024)
  )', table_name);

  -- Create the search function
  execute format('
  create function match_documents (
    query_embedding vector(1024),
    match_count int default null,
    filter jsonb default ''{}''
  ) returns table (
    id bigint,
    content text,
    metadata jsonb,
    similarity float
  ) language plpgsql as $$
  begin
    return query
    select
      id,
      content,
      metadata,
      1 - (''%I''.embedding <=> query_embedding) as similarity
    from %I
    where metadata @> filter
    order by ''%I''.embedding <=> query_embedding
    limit match_count;
  end;
  $$;', table_name, table_name, table_name);
end;
$$;

但是,当我运行这个函数时,遇到以下错误:

ERROR:  42601: syntax error at or near "#"
LINE 32:   #variable_conflict use_column
           ^

我尝试编写这样一个函数,但在创建时遇到了问题。另外,如果还有其他方法可以动态创建这些表,请建议!

sql postgresql plpgsql supabase dynamic-tables
1个回答
0
投票

在第二个示例中,打开函数体的

$$
与还在动态 SQL
$$
调用中打开另一个函数定义的
execute format(
匹配,留下孤立/错位的
#variable_conflict use_column
,我猜您之前有过那里,现在由于引号不匹配,它因其他一些令人困惑的错误而发生了变化。

命名的美元引号替换它们:例如,外部的用

$f1$
,内部的用
$f2$

db<>fiddle 的演示

create or replace function setup_vector_store(table_name text)
returns void language plpgsql as $f1$
begin
  execute format('
  create table %I (
    id bigint primary key generated always as identity,
    content text,
    metadata jsonb,
    embedding varchar(1024)
  )', table_name);

  execute 'drop function if exists match_documents(varchar(1024), int, jsonb)';
  execute format($dynsql$
  create function match_documents (
    query_embedding varchar(1024),
    match_count int default null,
    filter jsonb default ''{}''
  ) returns tsetof %1$I language plpgsql as $f2$
  begin
    return query
    select
      id,
      content,
      metadata,
      (1 - length(%1$I.embedding)-length(query_embedding))::float as similarity
    from %1$I
    where metadata @> filter
    order by length(%1$I.embedding)-length(query_embedding)
    limit match_count;
  end; $f2$; 
  $dynsql$, table_name);
end; $f1$;

请注意,如果您使用

%I 的位置表示法,则不必在 动态 SQL 调用
中重复 
format()
占位符。您可以多次重复使用
%1$I
,这意味着您需要 1st 参数作为 I 标识符。

我之前在这里评论过,

#
的事情需要在
begin
之前换行,结果证明这是错误的。

© www.soinside.com 2019 - 2024. All rights reserved.