SQL选择相邻集的相邻行

时间:2011-12-21 11:10:10

标签: sql postgresql

我在使用Postgres的SQL中执行以下操作时遇到了麻烦。我的程序有一组有序的数字。在我的数据库中,我有一个表,它存储了包含额外数据的行中的所有数字。这些行也按顺序排列。

例如我需要找的是我的套装;

1,5,6,1,3

数据库有行

row1 4
row2 5
row3 1
row4 5
row5 6
row6 1
row7 3
row8 2
row9 7

在上面的示例中,很容易看到我的集合从第3行到第7行。在SQL中仍然这样做对我来说是一个谜。我正在阅读一些有关数据透视表的文章,我仍然希望有一种更简单的方法。

4 个答案:

答案 0 :(得分:4)

两个数据集都需要包含标识订单的字段。

如果排序列是一组连续的连续数字,那么这是可能的,虽然我怀疑它很快。

Table 1                 Table 2

id | value              id | value
 1    4                  1    1
 2    5                  2    5
 3    1                  3    6
 4    5                  4    1
 5    6                  5    3
 6    1                  
 7    3                  
 8    2                  
 9    7                  

然后这个查询...

SELECT
  *
FROM
  table_1
INNER JOIN
  (
    SELECT
      MIN(table_1.id)    AS first_id,
      MAX(table_1.id)    AS last_id
    FROM
      table_1
    INNER JOIN
      table_2
        ON table_1.value = table_2.value
    GROUP BY
      table_1.id - table_2.id
    HAVING
      COUNT(*) = (SELECT COUNT(*) FROM table_2)
  )
  AS matched_sets
    ON  matched_sets.first <= table_1.id
    AND matched_sets.last  >= table_1.id

答案 1 :(得分:2)

递归版

@Dems打败了我: recursive CTE是这里的方法。它适用于任何数字序列。我发布我的版本是因为:

  • 它不需要额外的表格。只需将序列号插入数组即可。
  • 递归CTE本身更简单。
  • 最后的查询更聪明。
  • 它实际上适用于PostgreSQL。 @Dems递归版在其当前状态下在语法上是不正确的。

测试设置:

CREATE TEMP TABLE t (id int, val int);
INSERT INTO t VALUES
 (1,4),(2,5),(3,1)
,(4,5),(5,6),(6,1)
,(7,3),(8,2),(9,7);

呼叫:

WITH RECURSIVE x AS (
    SELECT '{1,5,6,1,3}'::int[] AS a
    ), y AS (
    SELECT t.id   AS start_id
          ,1::int AS step
    FROM   x
    JOIN   t ON t.val = x.a[1]

    UNION  ALL
    SELECT y.start_id
          ,y.step + 1                      -- AS step   -- next step
    FROM   y
    JOIN   t ON t.id = y.start_id + step   -- next id
    JOIN   x ON t.val = x.a[1 + step]      -- next value
    )
SELECT y.start_id
FROM   x
JOIN   y ON y.step = array_length(x.a, 1)  -- only where last steps was matched

结果:

3

静态版

适用于预定义数量的数组项,但对于小型数组更快。这种情况下有5个项目。与上面相同的测试设置。

WITH x AS (
    SELECT '{1,5,6,1,3}'::int[] AS a
    )
SELECT t1.id
FROM   x, t t1
JOIN   t t2 ON t2.id = t1.id + 1
JOIN   t t3 ON t3.id = t1.id + 2
JOIN   t t4 ON t4.id = t1.id + 3
JOIN   t t5 ON t5.id = t1.id + 4
WHERE  t1.val = x.a[1]
AND    t2.val = x.a[2]
AND    t3.val = x.a[3]
AND    t4.val = x.a[4]
AND    t5.val = x.a[5];

答案 2 :(得分:0)

怎么样......

Select instr(',' & Group_Concat(mNumber SEPARATOR ',') &',',@yourstring)
FROM Table

哎呀,我的SQL必须为Postgresql查找类似的函数......

Postgresql Version of Group_concat

所有这一切都是将多行组合成一个长字符串,然后执行“查找”以返回生成的长字符串中字符串的第一个位置。返回的数字将与row_number匹配。如果返回0,则表示字符串不在生成的字符串中。 (可能必须对','逗号空间保持谨慎。

答案 3 :(得分:0)

递归回答......

WITH
  CTE AS
(
  SELECT
    id        AS first_id,
    id        AS current_id,
    1         AS sequence_id
  FROM
    main_table
  WHERE
    value = (SELECT value FROM search_table WHERE id = 1)

  UNION ALL

  SELECT
    CTE.first_id,
    main_table.id,
    CTE.sequence_id + 1
  FROM
    CTE
  INNER JOIN
    main_table
      ON main_table.id = CTE.current_id + 1
  INNER JOIN
    search_table
      ON  search_table.value = main_table.value
      AND search_table.id    = CTE.sequence_id + 1
)
SELECT
  *
FROM
  main_table
INNER JOIN
  CTE
    ON  main_table.id >= CTE.first_id
    AND main_table.id <= CTE.current_id
WHERE
  CTE.sequence_id = (SELECT COUNT(*) FROM search_table)
相关问题