【问题标题】:Return five rows of random DNA instead of just one返回五行随机 DNA 而不是一
【发布时间】:2020-04-30 22:01:19
【问题描述】:

这是我必须创建一串 DNA 的代码:

prepare dna_length(int) as
  with t1 as (
    select chr(65) as s 
      union select chr(67) 
      union select chr(71) 
      union select chr(84) )
, t2 as ( select s, row_number() over() as rn from t1)
, t3 as ( select generate_series(1,$1) as i, round(random() * 4 + 0.5) as rn )
, t4 as ( select t2.s from t2 join t3 on (t2.rn=t3.rn))
select array_to_string(array(select s from t4),'') as dna;

execute dna_length(20);

我试图弄清楚如何重写它以给出一个包含 5 行 DNA 字符串的表,每行长度为 20,而不仅仅是一行。这是针对 PostgreSQL 的。

我试过了:

CREATE TABLE dna_table(g int, dna text);
INSERT INTO dna_table (1, execute dna_length(20));

但这似乎不起作用。我是一个绝对的初学者。如何正确执行此操作?

【问题讨论】:

    标签: sql postgresql random prepared-statement set-returning-functions


    【解决方案1】:

    PREPARE 创建一个可以“按原样”使用的准备好的语句。如果您准备好的语句返回一个字符串,那么您只能得到一个字符串。您不能在其他操作中使用它,例如插入,例如

    在您的情况下,您可以创建一个函数:

    create or replace function dna_length(int) returns text as
    $$
    with t1 as (
        select chr(65) as s
        union
        select chr(67)
        union
        select chr(71)
        union
        select chr(84))
       , t2 as (select s,
                       row_number() over () as rn
                from t1)
       , t3 as (select generate_series(1, $1)    as i,
                       round(random() * 4 + 0.5) as rn)
       , t4 as (select t2.s
                from t2
                         join t3 on (t2.rn = t3.rn))
    select array_to_string(array(select s from t4), '') as dna
    $$ language sql;
    

    并以这样的方式使用它:

    insert into dna_table(g, dna) select generate_series(1,5), dna_length(20)
    

    来自官方doc

    PREPARE 创建一个准备好的语句。准备好的语句是可用于优化性能的服务器端对象。当 PREPARE 语句被执行时,指定的语句被解析、分析和重写。当随后发出 EXECUTE 命令时,计划并执行准备好的语句。这种分工避免了重复的解析分析工作,同时允许执行计划依赖于提供的特定参数值。

    关于functions

    【讨论】:

      【解决方案2】:

      这可以更简单、更快:

      SELECT string_agg(CASE ceil(random() * 4)
                         WHEN 1 THEN 'A'
                         WHEN 2 THEN 'C'
                         WHEN 3 THEN 'T'
                         WHEN 4 THEN 'G'
                        END, '') AS dna
      FROM   generate_series(1,100) g  -- 100 = 5 rows * 20 nucleotides
      GROUP  BY g%5;
      

      random() 产生random value in the range 0.0 <= x < 1.0。乘以 4 并用ceil() 取数学上限(比round() 便宜),你会得到数字 1-4 的随机分布。转换为 ACTG,并与 GROUP BY g%5 - % being the modulo operator 聚合。

      关于string_agg()

      作为准备好的语句,取
      $1 ... 行数
      $2 ... 每行核苷酸数

      PREPARE dna_length(int, int) AS
      SELECT string_agg(CASE ceil(random() * 4)
                         WHEN 1 THEN 'A'
                         WHEN 2 THEN 'C'
                         WHEN 3 THEN 'T'
                         WHEN 4 THEN 'G'
                        END, '') AS dna
      FROM   generate_series(1, $1 * $2) g
      GROUP  BY g%$1;
      

      呼叫:

      EXECUTE dna_length(5,20);
      

      结果:

      |脱氧核糖核酸 | | :-------------------- | | ATCTTCGACACGTCGGTACC | | GTGGCTGCAGATGAACAGAG | | ACAGCTTAAAACACTAAGCA | | TCCGGACCTCTCGACCTTGA | | CGTGCGGAGTACCCTAATTA |

      db小提琴here

      如果您非常需要它,请考虑使用函数。见:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多