2016-12-30 4 views
-1

У меня есть сложный запрос для выполнения в большой таблице PostgreSQL. Вот пример данных:Поиск симметричных пар в PostgreSQL

enter image description here

Моя цель состоит в том, чтобы заполнить столбец to_from с характером y или n.

Давайте возьмем первую строку в качестве примера - значение в start = 48749 и значение в end = 50699. Если другая другая строка существует везде в таблице, где значения являются обратным, то есть, где end = 48749 и значение в start = 50699, я хотел бы заполнить столбециз обе строки с y. Если инверсия не существует, первая строка должна быть заполнена n. Ключ здесь состоит в том, чтобы перебирать каждую строку и искать ее обратную в таблице. Если найден обратный, необходимо ввести y. Однако, если имеется более одной строки, содержащей инверсию, только первая обратная строка должна получить y.

Я знаю, что я должен структурировать мой запрос по линии

SELECT * 
FROM mytable 
WHERE NOT EXISTS 
AND 
WHERE EXISTS 

Но я не уверен, как производить вывод я ищу. Должен ли я создать дубликатную таблицу и начать с нее? Любые указания о том, с чего начать или какие шаги предпринять?

Вот пример того, как должен выглядеть результат (если это было 10 строк). Как только запись используется для пары, ее нельзя использовать для другой.

Итак:

> my_table 
    ogc_fid track_fid start_gid end_gid to_from 
1  1   1  100  82  y 
2  2   2  82  100  y 
3  3   3  100  82  y 
4  4   4  100  32  n 
5  5   5  82  100  y 
6  6   6  82  100  y 
7  7   7  82  100  n 
8  8   8  100  82  y 
9  9   9  34  100  n 
10  10  10  31  100  n 
+0

'track_fid' является первичным ключом –

+0

вы можете вставить ваш стол в виде текста и показать, как результат должен выглядеть? также неясно, что вы подразумеваете под *, если есть несколько строк, содержащих инверсию, только первая обратная строка должна получить y *, где, как и в начале, вы говорите, что строки должны получить 'y'. –

+0

То, что я имею в виду, 'y' должно быть ограничено парой инверсий. Скажем (опять же используя первую строку в качестве примера), что есть три строки, где 'end' = 48749 и' start' = 50699. Только одна из этих строк должна получить 'y'. Наверное, это будет первый из этих трех. Имеет ли это смысл? –

ответ

0

Вы можете использовать greatest и least, чтобы получить отсчеты обратных строк. Если существует несколько таких строк, назначьте y первой такой паре, иначе назначьте n.

SELECT ogc_fid, 
     track_fid, 
     wkb_geo, 
     start_gid, 
     end_gid, 
     CASE 
      WHEN count(*) over(partition BY grtst,lst) > 1 THEN 'y' 
       --AND row_number() over(partition BY grtst,lst 
             --ORDER BY track_fid)<=2 THEN 'y' 
      WHEN count(*) over(partition BY grtst,lst) = 1 THEN 'n' 
     END AS to_from 
FROM 
    (SELECT ogc_fid, 
      track_fid, 
      wkb_geo, 
      start_gid, 
      end_gid, 
      greatest(start_gid,end_gid) AS grtst, 
      least(start_gid,end_gid) AS lst 
    FROM mytable) t 
+0

спасибо, что это последний символ 't' в конце запроса, ссылающегося на? –

+0

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

+0

и строки в выводе 'to_from', которые пусты,' n'? существует много пробелов –

0

Я думаю, что вы хотите использовать row_number(), а также join для идентификации первого среди матчей:

select t.*, 
     coalesce(t2.new_to_from, 'n') as new_to_from 
from (select t.*, 
      row_number() over (partition by start, end order by start) as seqnum 
     from t 
    ) t left join 
    (select t.*, 'y' as new_to_from, 
      row_number() over (partition by start, end order by start) as seqnum 
     from t 
    ) t2 
    on t2.start = t.end and t2.end = t.start and 
     t2.seqnum = 1 and t.seqnum = 1; 
+0

значит 't2' соответствует двойной таблице? –

+0

Это псевдоним таблицы, используемый для самостоятельного присоединения. –

+0

Я получаю сообщение об ошибке: «ERROR: синтаксическая ошибка в конце или рядом» LINE 4: ... row_number() over (раздел по началу, порядковый номер ... ' –

0

Запишите свои записи на start_gid и end_gid. Затем посмотрите на комбинации gid (100/82 = 82/100) с помощью LEAST и GREATEST и посмотрите, какие записи не имеют партнера (т. Е. Никакой другой записи в комбинации с номером этой строки).

select 
    ogc_fid, track_fid, start_gid, end_gid, to_from, 
    case when count(*) over (partition by small_gid, large_gid, rn) = 1 then 'n' else 'y' end 
from 
(
    select 
    ogc_fid, track_fid, start_gid, end_gid, to_from, 
    least(start_gid, end_gid) as small_gid, 
    greatest(start_gid, end_gid) as large_gid, 
    row_number() over(partition by start_gid, end_gid order by track_fid) as rn 
    from mytable 
) numbered; 
0

EXISTS() дает логическое значение, которое может быть использовано в CASE WHEN ... условном выражении:


UPDATE mytable t 
SET to_from = CASE WHEN EXISTS(SELECT * FROM mytable x 
          WHERE x.start_gid = t.end_gid 
          AND x.end_gid = t.start_gid) 
         AND NOT EXISTS(SELECT * FROM mytable nx 
          WHERE nx.start_gid = t.start_gid 
          AND nx.end_gid = t.end_gid 
          AND nx.ogc_fid > t.ogc_fid -- tie-breaker :: only the first will get a 'y' 
         ) 
       THEN 'y' ELSE 'n' END 
     ; 
Смежные вопросы