Postgres数组使用来自不同表

时间:2018-01-29 08:39:30

标签: sql postgresql

我有两个表,用户和组:

users(user_id BIGSERIAL, email TEXT UNIQUE NOT NULL, state TEXT NOT NULL)
groups(group_id BIGSERIAL, name TEXT, members []BIGINT)

从上面可以看出,users表包含一个用户记录,其中每个记录由电子邮件地址和自动生成的user_id字段唯一标识。 groups表包含一个members数组,其中包含一组引用users表中user_id的BIGINT。

现在我需要一个查询,当给出两个传入参数时,emailgroup_id

  1. 检查users表是否已包含具有该电子邮件地址的记录
  2. 如果没有行已包含该电子邮件地址,则
  3. INSERT新记录
  4. SELECT行的user_id(新创建或已存在)
  5. 附加上述步骤中获得的user_id,并将其附加到members与传入参数匹配的组表的group_id字段中。成员字段有可能已包含user_id,在这种情况下,不需要执行任何操作(IOW,members字段中的groups字段应该没有重复值}} table。。
  6. 对于1,2和3,我写了以下查询:

    WITH new_row AS (
        INSERT INTO users (email, state)
        SELECT 'abc@abc.abcd', 'Referred'
            WHERE NOT EXISTS (SELECT * FROM users WHERE email = 'abc@abc.abcd')
            RETURNING *
    )
    SELECT user_id FROM new_row
    UNION
    SELECT user_id FROM users WHERE email='abc@abc.abcd';
    

    对于4,我写了以下查询:

    UPDATE groups SET members = (
       SELECT ARRAY(
          SELECT DISTINCT unnest(members || array[RANDOM_USER_ID]::bigint[]) ) )
    WHERE group_id = INCOMING_GROUP_ID 
    RETURNING group_id, members;
    

    其中第二个查询中的RANDOM_USER_ID应替换为第一个查询中获得的user_id

    现在将这两个查询原子地组合为单个查询的方法是什么,其中第一个查询的user_id通过管道传输到第二个查询?我不想创建事务并独立运行两个单独的查询,并将user_id字段保存在临时位置(在我的服务器程序中)。我希望所有这些都可以在一个查询中完成。有可能吗?

    如果重要的话,我将在RDS / Google CloudSQL上使用Postgresql 9.6.4(或更高版本)。

1 个答案:

答案 0 :(得分:1)

从我看到的情况来看,我认为假设每个查询只有一个DECLARE @a VARCHAR(3); SET @a = ( SELECT TOP 1 sifval FROM ( SELECT sifval FROM VALUTI WHERE OZNVAL = 'EUR' UNION SELECT sifval FROM KURSNA WHERE OZNVAL = 'EUR' ) q ); 是公平的,所以你可以使用另一个CTE(为了清晰起见)和子查询:

user_id

替代方案是使用UPSERT:

WITH usr AS (
  WITH new_row AS (
      INSERT INTO users (email, state)
      SELECT 'abc@abc.abcd', 'Referred'
          WHERE NOT EXISTS (SELECT * FROM users WHERE email = 'abc@abc.abcd')
          RETURNING *
  )
  SELECT user_id FROM new_row
  UNION
  SELECT user_id FROM users WHERE email='abc@abc.abcd'
)
UPDATE groups SET members = (
   SELECT ARRAY(
      SELECT DISTINCT unnest(members || array[(SELECT user_id FROM usr)]::bigint[]) ) )
WHERE group_id = INCOMING_GROUP_ID 
RETURNING group_id, members;