Postgres LEFT JOIN和数据操作

时间:2014-03-20 19:33:05

标签: sql postgresql

我有一个无聊的问题要解决(希望这对我来说很难哈哈),如下:

我有一个包含许多表的PostgreSQL数据库。 这些表每天都由Perl脚本更新。 对我的问题感兴趣的表遵循以下模式:

   ID  |  Central  |     ts     |  Country   |  Name   | Column3 | Column4 | Column5 |
------------------------------------------------------------------------------------------

没有唯一的列主键标识行unicaly ... 相反,我可以在使用“ID-Central-ts”构建的Perl脚本中看到BTree作为PK。 “ts”是脚本生成的时间戳,DB中总有3个ts,因此它存储过去3天的每个“中心ID”行。

所以,我想要的: 放开“Country”和“Name”列(即使在相同的ID-central-ts中这些列也可能没有问题,甚至重复自己),一个“ID-Central-ts”不应该有不同的列'值那些在特定中心显示的。 我需要一个查询,向我显示这些值与右中心不匹配的最新时间戳添加(最大数字)。

我的意思是: 如果对于ID 01,“default-central”表示“column3”,“column4”和“column5”的值必须是最后一个“ts”中带有“right”的字符串,则应捕获任何不同的值。

示例:

假设Central'Alfa'是“默认中心”。 对于给定的ID,它存储的值必须等于此或任何其他Central中的每个“ID”。

   ID  |  Central  |     ts     | Country  |  Name    | Column3 | Column4 | Column5 |
------------------------------------------------------------------------------------------
   01  |   Alfa    |  10000001  |   USA    |  Fairy   |  right  |  right  |  right  |
   01  |   Alfa    |  10000002  |   USA    |  Minish  |  right  |  right  |  right  | 
   01  |   Alfa    |  10000003  |   USA    |  Elf     |  right  |  right  |  right  | 

   01  |   Delta   |  10000001  |   USA    |  Goron   |  right  |  right  |  right  | 
   01  |   Delta   |  10000002  |   USA    |  Elf     |  right  |  wrong  |  right  | 
   01  |   Delta   |  10000003  |   USA    |  Acqua   |  wrong  |  right  |  right  |
.
.
.
   02  |   Alfa    |  10000001  |   BRA    |  Fairy   |  RIGHT  |  RIGHT  |  RIGHT  |
   02  |   Alfa    |  10000002  |   BRA    |  Minish  |  RIGHT  |  RIGHT  |  RIGHT  | 
   02  |   Alfa    |  10000003  |   BRA    |  Elf     |  RIGHT  |  RIGHT  |  RIGHT  | 

   02  |   Delta   |  10000001  |   BRA    |  Goron   |  WRONG  |  RIGHT  |  RIGHT  | 
   02  |   Delta   |  10000002  |   BRA    |  Elf     |  RIGHT  |  WRONG  |  RIGHT  | 
   02  |   Delta   |  10000003  |   BRA    |  Acqua   |  WRONG  |  RIGHT  |  (null) |  

我需要得到:

   ID  |  Central  |     ts     | Country  |  Name    | Column3 | Column4 |   Column5     |
-------------------------------------------------------------------------------------------
   01  |   Delta   |  10000003  |   USA    |  Acqua   |  wrong  |         |               |
   02  |   Delta   |  10000003  |   BRA    |  Acqua   |  WRONG  |         |  "Wrong null" | 

即使ts 10000001或10000002的值不正确,也会看到它们没有被接收。 还要注意,当有空值应该存在一些值时,我需要写一些东西来表明这个null不应该存在。

任何人都可以看看吗? 我已经设法创建了一个视图来获取来自Alfa中心的值,但是我无法想象LEFT JOIN或者创建这些编写“错误null”事物的规则的方法,或者如何忽略较低的ts。

任何帮助都将受到高度赞赏。

3 个答案:

答案 0 :(得分:1)

我将采取的方式是自我加入:

SELECT t.*
FROM theTable AS m -- values from the "master" central
  INNER JOIN theTable AS t -- values from the central to test
     ON m.Central = 'ALFA'
    AND m.ts = (SELECT MAX(ts) FROM theTable)
    AND m.ID = t.ID
    AND m.ts = t.ts
    AND t.Central <> m.Central
    AND (
      -- we assume that values in the "master" central cannot be null or blank
      m.Column3 <> coalesce(t.Column3, '') OR 
      m.Column4 <> coalesce(t.Column4, '') OR 
      m.Column5 <> coalesce(t.Column5, '')
    )

在这种情况下,你也可以使用CTE,有些人会发现它们更具可读性:

WITH MaxTimestamp AS (
  SELECT MAX(tx) value FROM theTable
),
MasterValues AS (
  SELECT * FROM theTable WHERE Central = 'ALFA' AND ts = (SELECT value FROM MaxTimestamp)
), 
TestValues AS (
  SELECT * FROM theTable WHERE Central <> 'ALFA' AND ts = (SELECT value FROM MaxTimestamp)
)
SELECT t.*
FROM MasterValues m
  INNER JOIN TestValues t
     ON m.ID = t.ID
    AND (
      -- we assume that values in the "master" central cannot be null or blank
      m.Column3 <> coalesce(t.Column3, '') OR 
      m.Column4 <> coalesce(t.Column4, '') OR 
      m.Column5 <> coalesce(t.Column5, '')
    )

在任何一种情况下,您也可以将整个事物写为函数或匿名块,这样您就可以将主中心的值指定为参数或变量,以防不是固定值。

答案 1 :(得分:0)

应该是

select 
ID
,Central
,ts
,Country
,name
,COALESCE(column3, 'wrong') AS Column3
,COALESCE(column4, 'wrong') AS Column4
,COALESCE(column5, 'wrong') AS Column5
FROM T1
WHERE 
(UPPER(Column3) <> 'RIGHT' OR UPPER(Column4) <> 'RIGHT' OR UPPER(Column5) <> 'RIGHT')
and ts = (SELECT MAX(ts) FROM T1)

答案 2 :(得分:0)

我得到了LEFT JOIN的答案,其中包括我想要的每一个案例。

非常感谢每一条建议,并且对不接受我之前提出的任何答案感到遗憾...... 也许我还没有完全清楚,但我的答案提出了对我的问题的确切回应。

我不会更改查询以适应我以前用过的列名,因为我担心我会弄错。 我没有创建大量的AND,而是决定逐列获取每个差异,然后在FULL OUTER JOIN中加入它们的所有差异。

按照我的第一个查询,获取与给定中心不同的值。

SELECT Test_Configs.central, Test_Configs.imsi,
       CASE Test_Configs.mapver WHEN '' THEN '-'
           ELSE COALESCE(Test_Configs.mapver, '-') 
       END 

FROM config_imsis_centrais AS Default_Configs              -- Valores padrão da central correta
    LEFT JOIN config_imsis_centrais AS Test_Configs        -- Valores das centrais a serem testadas
        ON Default_Configs.central = 'CENTRAL_USED_AS_EXAMPLE'

        AND Default_Configs.ts = (SELECT MAX(ts) FROM config_imsis_centrais)
        AND Default_Configs.imsi = Test_Configs.imsi
        AND Default_Configs.ts = Test_Configs.ts
        AND Test_Configs.central <> Default_Configs.central
WHERE (                                                    -- Análise:
            COALESCE(Default_Configs.mapver, 'null') <> COALESCE(Test_Configs.mapver, 'null') AND

            Test_Configs.central <> ''
       )

我的全部加入加入是通过加入每个潜在表格,使用中心和“imsi”,(就像我的例子中的ID一样)。如下:

SELECT central, imsi, mapver, camel, nrrg
    FROM
        vw_erros_mgisp_mapver 
        FULL OUTER JOIN
        vw_erros_mgisp_camel USING (central, imsi)
        FULL OUTER JOIN
        vw_erros_mgisp_nrrg USING (central, imsi)
    ORDER BY central, imsi

就是这样。非常感谢大家,不好意思不接受你努力工作的答案,我认为对于有同样问题的人研究更好的解决方案会更好。

干杯!