返回五行随机 DNA 而不是一

Posted

技术标签:

【中文标题】返回五行随机 DNA 而不是一【英文标题】:Return five rows of random DNA instead of just one 【发布时间】: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));

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

【问题讨论】:

【参考方案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()

Concatenate multiple result rows of one column into one, group by another column

作为准备好的语句,取$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

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

What is the difference between a prepared statement and a SQL or PL/pgSQL function, in terms of their purposes?

【讨论】:

以上是关于返回五行随机 DNA 而不是一的主要内容,如果未能解决你的问题,请参考以下文章

干支纪年算法

Python|基于百度API五行代码实现OCR文字高识别率

怎样在.net的GridView中每五行空一行或者显示分割线?

如何正确使用熊猫打印前五行[重复]

十二生旺死绝表配纳音五行

Go Live! | 名无虚《五行》即兴民乐,民乐还能这样玩!