【问题标题】:Postgres FOR LOOPPostgres FOR 循环
【发布时间】:2013-10-09 08:36:29
【问题描述】:

我正在尝试从表中获取 15,000 个 ID 的 25 个随机样本。我不是每次都手动按下运行,而是尝试循环。我完全理解不是 Postgres 的最佳使用,但它是我拥有的工具。这是我目前所拥有的:

for i in 1..25 LOOP
   insert into playtime.meta_random_sample
   select i, ID
   from   tbl
   order  by random() limit 15000
end loop

【问题讨论】:

    标签: postgresql stored-procedures for-loop random plpgsql


    【解决方案1】:

    使用过程。

    CREATE or replace PROCEDURE pg_temp_3.insert_data()
    LANGUAGE SQL
    BEGIN ATOMIC
    INSERT INTO meta_random_sample(col_serial, parent_id)
    SELECT t.*
    FROM   generate_series(1,25) i
    CROSS  JOIN LATERAL (
       SELECT i, parent_id
       FROM    parent_tree order by random() limit 2
       ) t;
    END;
    

    调用过程。

    call pg_temp_3.insert_data();
    

    PostgreSQL 手册:https://www.postgresql.org/docs/current/sql-createprocedure.html

    【讨论】:

      【解决方案2】:

      Procedural elements like loops 不是 SQL 语言的一部分,只能在过程语言 functionprocedure(Postgres 11 或更高版本)或 DO 语句的主体内使用,其中此类附加元素是由各自的程序语言定义。默认是PL/pgSQL,但是there are others

      plpgsql 示例:

      DO
      $do$
      BEGIN 
         FOR i IN 1..25 LOOP
            INSERT INTO playtime.meta_random_sample
               (col_i, col_id)                       -- declare target columns!
            SELECT  i,     id
            FROM   tbl
            ORDER  BY random()
            LIMIT  15000;
         END LOOP;
      END
      $do$;
      

      对于许多可以通过循环解决的任务,有一个更短、更快的基于集合的解决方案。您的示例的纯 SQL 等效项:

      INSERT INTO playtime.meta_random_sample (col_i, col_id)
      SELECT t.*
      FROM   generate_series(1,25) i
      CROSS  JOIN LATERAL (
         SELECT i, id
         FROM   tbl
         ORDER  BY random()
         LIMIT  15000
         ) t;
      

      关于generate_series()

      关于优化随机选择的性能:

      【讨论】:

        【解决方案3】:

        我发现使用过程编程语言(如 Python)建立连接并执行这些类型的查询更方便。

        import psycopg2
        connection_psql = psycopg2.connect( user="admin_user"
                                          , password="***"
                                          , port="5432"
                                          , database="myDB"
                                          , host="[ENDPOINT]")
        cursor_psql = connection_psql.cursor()
        
        myList = [...]
        for item in myList:
          cursor_psql.execute('''
            -- The query goes here
          ''')
        
        connection_psql.commit()
        cursor_psql.close()
        

        【讨论】:

        • 我也在想同样的事情,但是当您需要对数据库进行大量调用时,它可能会成为一个问题。
        【解决方案4】:

        我刚遇到这个问题,虽然它很旧,但我想我会为档案添加一个答案。 OP 询问了 for 循环,但他们的目标是从表中收集随机的行样本。对于该任务,Postgres 9.5+ 在 WHERE 上提供了 TABLESAMPLE 子句。这是一个很好的概要:

        https://www.2ndquadrant.com/en/blog/tablesample-in-postgresql-9-5-2/

        我倾向于使用 Bernoulli,因为它是基于行而不是基于页面的,但最初的问题是关于特定的行数。为此,有一个内置扩展:

        https://www.postgresql.org/docs/current/tsm-system-rows.html

        CREATE EXTENSION tsm_system_rows;
        

        然后你可以获取任意数量的行:

        select * from playtime tablesample system_rows (15);
        

        【讨论】:

          【解决方案5】:

          以下是您可以使用的示例:

          create temp table test2 (
            id1  numeric,
            id2  numeric,
            id3  numeric,
            id4  numeric,
            id5  numeric,
            id6  numeric,
            id7  numeric,
            id8  numeric,
            id9  numeric,
            id10 numeric) 
          with (oids = false);
          
          do
          $do$
          declare
               i int;
          begin
          for  i in 1..100000
          loop
              insert into test2  values (random(), i * random(), i / random(), i + random(), i * random(), i / random(), i + random(), i * random(), i / random(), i + random());
          end loop;
          end;
          $do$;
          

          【讨论】:

            猜你喜欢
            • 2019-01-13
            • 1970-01-01
            • 2022-06-13
            • 1970-01-01
            • 1970-01-01
            • 2023-02-17
            • 2020-07-10
            • 2011-10-18
            • 1970-01-01
            相关资源
            最近更新 更多