Postgresql 根据默认顺序连接2个集合

Postgresql 根据默认顺序连接2个集合,postgresql,Postgresql,如何仅根据默认顺序连接两组记录 如果我有一个表x(col(1,2,3,4,5,6,7))和另一个表z(col(a,b,c,d,e,f,g)) 它会回来的 c1 c2 -- -- 1 a 2 b 3 c 4 d 5 e 6 f 7 g 实际上,我想从参数连接一对一维数组,并将它们视为表中的列 示例代码: CREATE OR REPLACE FUNCTION "Test"(timestamp without time zone[],

如何仅根据默认顺序连接两组记录

如果我有一个表x(col(1,2,3,4,5,6,7))和另一个表z(col(a,b,c,d,e,f,g))

它会回来的

c1 c2
-- --    
1   a
2   b
3   c
4   d
5   e
6   f
7   g
实际上,我想从参数连接一对一维数组,并将它们视为表中的列

示例代码:

CREATE OR REPLACE FUNCTION "Test"(timestamp without time zone[],
                                  timestamp without time zone[])
  RETURNS refcursor AS
$BODY$
DECLARE
curr refcursor;
BEGIN
    OPEN curr FOR 
        SELECT DISTINCT "Start" AS x, "End" AS y, COUNT("A"."id") 
        FROM UNNEST($1) "Start" 
        INNER JOIN 
        (
            SELECT "End", ROW_NUMBER() OVER(ORDER BY ("End")) rn
                FROM UNNEST($2) "End" ORDER BY ("End") 
        ) "End" ON ROW_NUMBER() OVER(ORDER BY ("Start")) = "End".rn 
        LEFT JOIN "A" ON ("A"."date" BETWEEN x AND y) 
        GROUP BY 1,2 
        ORDER BY "Start";
    return curr;
END

$BODY$
如果
x.c1
不是
1,2,3…
您可以执行与
z
相同的操作


正如Erwin所指出的,中间的顺序是不必要的。我是这样测试的:

create table t (i integer);
insert into t
select ceil(random() * 100000)
from generate_series(1, 100000);

select
    i,
    row_number() over(order by i) rn
from t
;
然后,
i
按顺序出现。在这个我从未执行过的简单测试之前,我认为行可以按任何顺序编号

如果
x.c1
不是
1,2,3…
您可以执行与
z
相同的操作


正如Erwin所指出的,中间的顺序是不必要的。我是这样测试的:

create table t (i integer);
insert into t
select ceil(random() * 100000)
from generate_series(1, 100000);

select
    i,
    row_number() over(order by i) rn
from t
;
然后,
i
按顺序出现。在这个我从未执行过的简单测试之前,我认为行可能以任何顺序进行编号。

按“默认顺序”听起来,您可能是指通过
select*from tablename
返回行的顺序,而不使用
order By

如果是,则此顺序未定义。数据库可以按其感觉的任何顺序返回行。您会发现,如果更新一行,它可能会移动到表中的不同位置

如果您陷于假定表有顺序但没有顺序的情况,则可以根据表中元组的磁盘顺序添加行号作为恢复选项:

select row_number() OVER (), *
from the_table
order by ctid
如果输出看起来正确,我建议您
创建一个带有额外字段的新表
,然后执行
插入到。。。选择
插入按ctid排序的数据,然后选择ALTER TABLE。。。重命名表,最后修复所有外键引用,使它们指向新表

ctid
可以通过autovacuum、
UPDATE
CLUSTER
等进行更改,因此您不应该在应用程序中使用它。我在这里使用它只是因为它听起来好像没有任何真正的排序或标识符键

如果需要根据行在磁盘上的顺序(如上所述,这是一种不可靠且不安全的做法)对行进行配对,可以尝试:

但千万不要在生产应用程序中依赖这一点。如果您真的陷入困境,您可以将其与
CREATE TABLE AS
一起使用,以构建一个新表,当您正在从缺少所需键的数据库恢复数据时,可以从该表开始,但仅此而已

当使用缺少ctid的集合(如函数的临时结果)时,上面给出的相同方法可能适用于空窗口子句
()
,而不是
(按ctid排序)
。不过,它的安全性甚至更低,应该是最后的选择

(另请参见这个较新的相关答案:)

按“默认顺序”听起来,您可能指的是
select*from tablename
返回行的顺序,没有
order By

如果是,则此顺序未定义。数据库可以按其感觉的任何顺序返回行。您会发现,如果更新一行,它可能会移动到表中的不同位置

如果您陷于假定表有顺序但没有顺序的情况,则可以根据表中元组的磁盘顺序添加行号作为恢复选项:

select row_number() OVER (), *
from the_table
order by ctid
如果输出看起来正确,我建议您
创建一个带有额外字段的新表
,然后执行
插入到。。。选择
插入按ctid排序的数据,然后选择ALTER TABLE。。。重命名表,最后修复所有外键引用,使它们指向新表

ctid
可以通过autovacuum、
UPDATE
CLUSTER
等进行更改,因此您不应该在应用程序中使用它。我在这里使用它只是因为它听起来好像没有任何真正的排序或标识符键

如果需要根据行在磁盘上的顺序(如上所述,这是一种不可靠且不安全的做法)对行进行配对,可以尝试:

但千万不要在生产应用程序中依赖这一点。如果您真的陷入困境,您可以将其与
CREATE TABLE AS
一起使用,以构建一个新表,当您正在从缺少所需键的数据库恢复数据时,可以从该表开始,但仅此而已

当使用缺少ctid的集合(如函数的临时结果)时,上面给出的相同方法可能适用于空窗口子句
()
,而不是
(按ctid排序)
。不过,它的安全性甚至更低,应该是最后的选择

(另请参见这个较新的相关答案:)

现在,回答评论中揭示的真实问题,它似乎类似于:

给定两个数组“a”和“b”,如何将它们的元素配对,以便在查询中获得作为列别名的元素对

有几种方法可以解决这个问题:

  • 如果且仅当数组长度相等时,在
    SELECT
    子句中使用多个
    unnest
    函数(一种不推荐使用的方法,仅用于向后兼容)

  • 使用
    generate_subscripts
    在数组上循环

  • 如果您需要支持太旧的版本而无法使用
    生成下标,请在子查询上对
    数组下标
    数组上标
    使用
    生成下标

  • 依赖于
    unnest
    返回元组的顺序和我的另一个答案中的hope-like,如下所示。它可以工作,但不能保证在未来工作
    CREATE OR REPLACE FUNCTION arraypair (a integer[], b text[]) 
    RETURNS TABLE (col_a integer, col_b text) AS $$
      -- blah code here blah
    $$ LANGUAGE whatever IMMUTABLE;
    
    SELECT * FROM arraypair( ARRAY[1,2,3,4,5,6,7], ARRAY['a','b','c','d','e','f','g'] );
    
    CREATE OR REPLACE FUNCTION arraypair (a integer[], b text[])
    RETURNS TABLE (col_a integer, col_b text) AS $$
        SELECT unnest(a), unnest(b);
    $$ LANGUAGE sql IMMUTABLE;
    
    CREATE OR REPLACE FUNCTION arraypair (a integer[], b text[])
    RETURNS TABLE (col_a integer, col_b text) AS $$
        SELECT
           a[i], b[i]
        FROM generate_subscripts(CASE WHEN array_length(a,1) >= array_length(b,1) THEN a::text[] ELSE b::text[] END, 1) i;
    $$ LANGUAGE sql IMMUTABLE;
    
    CREATE OR REPLACE FUNCTION arraypair (a integer[], b text[])
    RETURNS TABLE (col_a integer, col_b text) AS $$
     WITH
        rn_c1(rn, col) AS (
          SELECT row_number() OVER (), c1.col
          FROM unnest(a) c1(col) 
        ),
        rn_c2(rn, col) AS (
          SELECT row_number() OVER (), c2.col
          FROM unnest(b) c2(col)
        )
        SELECT
          rn_c1.col AS c1, 
          rn_c2.col AS c2
        FROM rn_c1 
        INNER JOIN rn_c2 ON (rn_c1.rn = rn_c2.rn);
    $$ LANGUAGE sql IMMUTABLE;
    
    SELECT * FROM unnest(a,b);