2016-12-30 18 views
-1

我有一個複雜的查詢在大型PostgreSQL表上執行。下面是數據的一個樣本:在PostgreSQL中查找對稱對

enter image description here

我的目標是與人物yn填充柱to_from

讓我們的第一行作爲一個例子 - 在start = 48749的值,並在end = 50699.值如果另一其他行中,其中的值是逆表中存在任何地方,即,其中end = 48749和值start = 50699,我想填寫列to_from行與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

您可以使用greatestleast獲得數相反的行。如果存在多於一個這樣的行,則將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

我得到的錯誤:'錯誤:語法錯誤在或接近「結束」 線4:... row_number()在(分區開始,結束順序...' –

0

根據start_gid和end_gid記錄您的記錄數。然後通過使用LEASTGREATEST查看gid組合(100/82 = 82/100),並查看哪些記錄沒有夥伴(即沒有與該行號組合的其他記錄)。

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 
     ;