SQL выбирает соседние строки для смежного набора - PullRequest
4 голосов
/ 21 декабря 2011

У меня проблемы с выполнением следующих действий в SQL с Postgres.В моей программе есть упорядоченный набор чисел.В моей базе данных есть таблица, в которой хранятся все числа в строках с дополнительными данными.Эти строки также расположены по порядку.

Например, мой набор, который мне нужно найти:

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 ]

4 голосов
/ 21 декабря 2011

Оба набора данных должны иметь поля, определяющие порядок.

И при условии, что столбец порядка представляет собой последовательный последовательный набор чисел, тогда это возможно, хотя я сомневаюсь, что это очень быстро.

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
2 голосов
/ 21 декабря 2011

Рекурсивная версия

@ Демс побеждает меня к этому: рекурсивный 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];
0 голосов
/ 21 декабря 2011

Рекурсивный ответ ...

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)
0 голосов
/ 21 декабря 2011

как насчет ...

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

Ой, это мой SQL, нужно искать похожие функции для Postgresql ...

Postgresql версия Group_concat

Все, что это делает, это группирует несколько строк в одну длинную строку, а затем выполняет «Поиск», чтобы вернуть первую позицию вашей строки в сгенерированной длинной строке. Возвращенное число будет соответствовать row_number. Если возвращается 0, ваша строка не в сгенерированной. (возможно, следует быть осторожным с пробелом ','.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...