postgresql 在Postgres表中插入虚拟数据

disbfnqx  于 2023-10-18  发布在  PostgreSQL
关注(0)|答案(3)|浏览(161)

下面是一个Postgres表:

create table test (
    id serial, 
    contract varchar, 
    amount0 int, 
    amount1 int, 
    price double precision
);

我想插入100行符合以下要求的虚拟数据:

  • 在“合同”列中,应该有“abc”、“klm”和“xyz”之外的值。
  • 在列“”0“和”“1”中,应该有50、60、80、100、200中的整数值。
  • 在“价格”列中,应该有1.5、1.8、2.1、2.5中的值。
    到目前为止,我得出的结论是:
INSERT INTO test (amount0, amount1, price)
SELECT
  (SELECT val FROM unnest(ARRAY[50, 60, 80, 100, 200]) AS val ORDER BY random() LIMIT 1),
  (SELECT val FROM unnest(ARRAY[50, 60, 80, 100, 200]) AS val ORDER BY random() LIMIT 1),
  (SELECT val FROM unnest(ARRAY[1.5, 1.8, 2.1, 2.5]) AS val ORDER BY random() LIMIT 1)
FROM generate_series(1, 100);

但这并不管用。此语句始终只对列“price”使用“100”,对列“price”使用“50”,对列“price”使用“2.1”。
有人能帮帮我吗?

cfh9epnr

cfh9epnr1#

你可以随机下标选择数组:(demo

INSERT INTO test (contract,amount0, amount1, price)
SELECT (ARRAY['abc','klm','xyz'])[(random()*2+1)::int],
       (ARRAY[50, 60, 80, 100, 200])[(random()*4+1)::int],
       (ARRAY[50, 60, 80, 100, 200])[(random()*4+1)::int],
       (ARRAY[1.5, 1.8, 2.1, 2.5])[(random()*3+1)::int]
FROM generate_series(1, 1e2, 1);

SELECT id, contract,amount0, amount1, price FROM test LIMIT 6;

| ID|合同|联系我们|金额1|价格|
| --|--|--|--|--|
| 1 |KLM| 50 | 100 |2.1|
| 2 |xyz| 100 | 100 |1.5|
| 3 |ABC| 80 | 100 |1.8|
| 4 |xyz| 80 | 80 |2.1|
| 5 |xyz| 200 | 50 |1.8|
| 6 |xyz| 60 | 60 |1.8|
请注意,这是您打算做的,使每个选择独立随机。实际上,您很可能会得到重复的条目。如果你更喜欢不断获得独特的组合,直到你用完,然后才重新开始,你可以做一些类似于迈克的建议:(demo2

INSERT INTO test (contract,amount0, amount1, price)
SELECT contract,amount0, amount1, price
FROM (values (50),(60),(80),(100),(200)) a(amount0),
     (values (50),(60),(80),(100),(200)) b(amount1),
     (values (1.5), (1.8), (2.1), (2.5)) c(price),
     (values ('abc'),('klm'),('xyz')   ) d(contract),
     generate_series(1, 1e2, 1) duplicator(n)
order by n, random()
limit 100;

Here's a function如果你发现自己需要一个 * 加权 * 随机数,这意味着你想确切地定义一个选项与其他选项相比的可能性。
您的解决方案不起作用的原因是,由于标量子查询不以任何方式依赖于外部查询,因此它们只被计算一次并被重用。您可以通过使用explain analyze verbose运行它来检查计划。您可以通过添加外部引用来欺骗规划器,使其认为他们在某种程度上依赖于外部查询,即使它什么也不做(demo3),但上面的代码也是一样的,代码更少。

piah890a

piah890a2#

问题是每次你运行你的命令时,PostgreSQL都会取一个种子号并将其发送给srand函数。这就是为什么使用相同的种子,您可以从数组中获得相同的值。因此,你需要调用函数,只要你想从数组中得到另一个值,你就可以创建函数。这将导致上下文切换,但这是我唯一能想到的。也许别人可以纠正我。代码如下:

create table test (
    id serial, 
    contract varchar, 
    amount0 int, 
    amount1 int, 
    price double precision
);

CREATE OR REPLACE FUNCTION random_amount()
  RETURNS int
  LANGUAGE sql VOLATILE PARALLEL SAFE AS
$func$
  SELECT ('[0:4]={50, 60, 80, 100, 200}'::int[])[trunc(random()  * (4 - 1 + 1) + 1)::int];
$func$;

CREATE OR REPLACE FUNCTION random_price()
  RETURNS int
  LANGUAGE sql VOLATILE PARALLEL SAFE AS
$func$
  (SELECT ('[0:3]={1.5, 1.8, 2.1, 2.5}'::float[])[trunc(random()  * (3 - 1 + 1) + 1)::int]);
$func$;

INSERT INTO test (amount0, amount1, price)
SELECT
  random_amount(), random_amount(), random_price()
FROM generate_series(1, 100);

select * from test;

Fiddle.

k4emjkb1

k4emjkb13#

您的查询在正确的轨道上,可以为'price 0'、'price 1'和'price'列生成随机值。若要同时包含值为'abc'、'klm'和'xyz'的'contract'列,您可以按如下方式修改查询:

INSERT INTO test (contract, amount0, amount1, price)
SELECT
  CASE 
    WHEN random() < 0.33 THEN 'abc'
    WHEN random() < 0.66 THEN 'klm'
    ELSE 'xyz'
  END AS contract,
  (SELECT val FROM unnest(ARRAY[50, 60, 80, 100, 200]) AS val ORDER BY random() LIMIT 1),
  (SELECT val FROM unnest(ARRAY[50, 60, 80, 100, 200]) AS val ORDER BY random() LIMIT 1),
  (SELECT val FROM unnest(ARRAY[1.5, 1.8, 2.1, 2.5]) AS val ORDER BY random() LIMIT 1)
FROM generate_series(1, 100);

SELECT id, contract, amount0, amount1, price FROM test LIMIT 6;

此查询使用CASE语句根据概率为“contract”列随机选择值。它为每一行分配概率大致相等的“abc”、“klm”或“xyz”。

相关问题