【问题标题】:Query select rows based on distinct values of a column根据列的不同值查询选择行
【发布时间】:2015-06-30 08:51:54
【问题描述】:

我的当前查询有问题,我希望根据列获取记录/结果(如果有 3 条状态为新的记录,则我执行的查询的状态示例列的值为新/待处理/已完成,它应该被过滤以仅显示状态为新的 1 条记录)。下面是我当前的查询,它得到了重复的列。

select a.CW_UPD_TMS,
          case when a.CW_CRT_UID='AAA' then 'BBB'
               else a.CW_CRT_UID end as CW_CRT_UID,  
          COALESCE(b.CW_S_BR, a.CW_S_BR) as CW_S_BR,
          a.CW_TRX_STAT as STATUS,   
          SUBSTR(a.CW_UPD_TMS,7,2) as day,
          SUBSTR(a.CW_UPD_TMS,5,2) as month,
          SUBSTR(a.CW_UPD_TMS,1,4) as ayear,   
          SUBSTR(a.CW_UPD_TMS,9,2) as hours,
          SUBSTR(a.CW_UPD_TMS,11,2) as mins,
          SUBSTR(a.CW_UPD_TMS,13,2) as secs,   
          case when cast(SUBSTR(a.CW_UPD_TMS,9,2) as INT) > 12 then 'PM'
               else 'AM' end as zone   
from  TABLEA  a  
    left outer join TABLEB b on a.CW_CRT_UID = b.CW_S_USR  
where a.CW_TRX_ID = '20150415110000798' 
union  
select a.CW_UPD_TMS,
          case when a.CW_CRT_UID='AAA' then 'BBB'
               else a.CW_CRT_UID end as CW_CRT_UID,  
          COALESCE(b.CW_S_BR, a.CW_S_BR) as CW_S_BR,
          a.CW_TRX_STAT as STATUS,   
          SUBSTR(a.CW_UPD_TMS,7,2) as day,
          SUBSTR(a.CW_UPD_TMS,5,2) as month,
          SUBSTR(a.CW_UPD_TMS,1,4) as ayear,   
          SUBSTR(a.CW_UPD_TMS,9,2) as hours,
          SUBSTR(a.CW_UPD_TMS,11,2) as mins,
          SUBSTR(a.CW_UPD_TMS,13,2) as secs,   
          case when cast(SUBSTR(a.CW_UPD_TMS,9,2) as INT) > 12 then 'PM'
               else 'AM' end as zone   
from  TABLEC  a  
    left outer join TABLEB b on a.CW_CRT_UID = b.CW_S_USR  
where a.CW_TRX_ID = '20150415110000798'

这是当前结果:

CW_UPD_TMS          CW_CRT_UID  CW_S_BR STATUS  DAY MONTH   AYEAR   HOURS   MINS    SECS    ZONE
2015062610260746811 happy       KLC     NEW     26  06      2015    10      26      07      AM
2015062610273984711 happy       KLC     NEW     26  06      2015    10      27      39      AM
2015062610275762511 happy       KLC     NEW     26  06      2015    10      27      57      AM

所以现在我该如何更改查询,以便只显示 1 条记录(以 min(CW_UPD_TMS) 显示),因为现在 3 条记录具有相同的状态(新)。

我的预期结果应该是:

CW_UPD_TMS          CW_CRT_UID  CW_S_BR STATUS  DAY MONTH   AYEAR   HOURS   MINS    SECS    ZONE
2015062610260746811 happy       KLC     NEW     26  06      2015    10      26      07      AM

对不起我糟糕的英语。

【问题讨论】:

  • 执行 UNION 时不必指定 DISTINCT,因为 UNION 会删除重复的行。
  • 因此,如果它们的状态不同,您仍然希望看到那些行保留每个组中具有最早时间戳的行吗?
  • 不要将日期或时间戳存储为字符,使用 DATE 或 TIMESTAMP 数据类型!
  • 另外,case when b.CW_S_BR is null then a.CW_S_BR else b.CW_S_BR end可以写成COALESCE(b.CW_S_BR, a.CW_S_BR),这样更清楚。
  • 也许您需要具有 NEW 状态的“最旧”行?还是“较新”的? DISTINCTUNION 基本上是在做他们的工作:你提供的三行是不同的。

标签: sql derby squirrel-sql


【解决方案1】:

它在您的情况下的预期行为。除了“状态”之外,您还应该提出另一列,这样它们就可以形成复合键,这将是唯一的,并且您会获得一条记录。

您可以有任何标准,如日期或任何适合您要求的标准,并使用行号属性将结果限制为 1 条记录。

让我知道这是否有意义。

【讨论】:

  • 您好,我认为您的方式可行,但我无法更改表格设计:(
【解决方案2】:

要获取最旧的记录,您需要按日期对记录进行排名。所以你要做的就是结合 TableA 和 TableC,给记录一个数字,每个状态最旧的记录为 1,然后只保留这些记录排名 1。

select a.cw_upd_tms,
  case when a.cw_crt_uid='AAA' then 'BBB'
       else a.cw_crt_uid end as cw_crt_uid,  
  coalesce(b.cw_s_br, a.cw_s_br) as cw_s_br,
  a.cw_trx_stat as status,   
  substr(a.cw_upd_tms,7,2) as day,
  substr(a.cw_upd_tms,5,2) as month,
  substr(a.cw_upd_tms,1,4) as ayear,   
  substr(a.cw_upd_tms,9,2) as hours,
  substr(a.cw_upd_tms,11,2) as mins,
  substr(a.cw_upd_tms,13,2) as secs,   
  case when cast(substr(a.cw_upd_tms,9,2) as int) > 12 then 'PM'
       else 'AM' end as zone   
from 
(
  select 
    cw_trx_stat, cw_crt_uid, cw_upd_tms
  from
  (
    select 
      cw_trx_stat, cw_crt_uid, cw_upd_tms,
      row_number() over (partition by cw_trx_stat order by cw_upd_tms) as rn
    from
    (
      select cw_trx_stat, cw_crt_uid, cw_upd_tms
      from tablea where cw_trx_id = '20150415110000798' 
      union all
      select cw_trx_stat, cw_crt_uid, cw_upd_tms
      from tablec where cw_trx_id = '20150415110000798' 
    ) combined
  ) ranked
  where rn = 1
) a
left outer join tableb b on a.cw_crt_uid = b.cw_s_usr;

【讨论】:

  • 很抱歉,我的 DBMS 是 Derby,我在 Squirrel SQL 上运行查询
  • 好的,所以不是 SQL Server,而是 Apache Derby。上面的查询是标准 SQL。其中最先进的是分析函数 ROW_NUMBER,Derby 从 10.4 版开始支持该函数。你试过查询吗?
  • 执行期间发生命中错误 - 错误:语法错误:在第 22 行第 26 列遇到“分区”。
  • 在告诉您 ROW_NUMBER 从版本 10.4 开始在 Derby 中可用后,我从您那里得知您在该行中遇到语法错误。你能猜到我的下一个问题吗?
【解决方案3】:

这可能是一个好的开始,但我不得不假设时间戳作为主键。您应该在问题中提及您所在的平台。如果我们了解连接和联合发生了什么,它也可能更清晰。

select
    d.CW_UPD_TMS, CW_CRT_UID, CW_S_BR, STATUS, day, month, ayear, hours, mins, secs, zone   
from 
(
    select
        a.CW_UPD_TMS, case when a.CW_CRT_UID='AAA' then 'BBB' else a.CW_CRT_UID end as CW_CRT_UID,  
        case when b.CW_S_BR is null then a.CW_S_BR else b.CW_S_BR end as CW_S_BR, a.CW_TRX_STAT as STATUS,   
        SUBSTR(a.CW_UPD_TMS,7,2) as day, SUBSTR(a.CW_UPD_TMS,5,2) as month, SUBSTR(a.CW_UPD_TMS,1,4) as ayear,   
        SUBSTR(a.CW_UPD_TMS,9,2) as hours, SUBSTR(a.CW_UPD_TMS,11,2) as mins,SUBSTR(a.CW_UPD_TMS,13,2) as secs,   
        case when cast(SUBSTR(a.CW_UPD_TMS,9,2) as INT) > 12 then 'PM' else 'AM' end as zone   
    from TABLEA a left outer join TABLEB b on a.CW_CRT_UID = b.CW_S_USR  
    where a.CW_TRX_ID = '20150415110000798' 
    union  
    select
        a.CW_UPD_TMS, case when a.CW_CRT_UID='AAA' then 'BBB' else a.CW_CRT_UID end as CW_CRT_UID,  
        case when b.CW_S_BR is null then a.CW_S_BR else b.CW_S_BR end as CW_S_BR, a.CW_TRX_STAT as STATUS,   
        SUBSTR(a.CW_UPD_TMS,7,2) as day, SUBSTR(a.CW_UPD_TMS,5,2) as month, SUBSTR(a.CW_UPD_TMS,1,4) as ayear,   
        SUBSTR(a.CW_UPD_TMS,9,2) as hours, SUBSTR(a.CW_UPD_TMS,11,2) as mins,SUBSTR(a.CW_UPD_TMS,13,2) as secs,   
        case when cast(SUBSTR(a.CW_UPD_TMS,9,2) as INT) > 12 then 'PM' else 'AM' end as zone   
    from TABLEC a  
    left outer join TABLEB b on a.CW_CRT_UID = b.CW_S_USR  
    where a.CW_TRX_ID = '20150415110000798'
) as d /* data */ inner join
(
    select min(CW_UPD_TMS) as CW_UPD_TMS, CW_TRX_STAT
    from (
        select a.CW_UPD_TMS, a.CW_TRX_STAT
        from TABLEA a
        where a.CW_TRX_ID = '20150415110000798' 
        union  
        select c.CW_UPD_TMS, c.CW_TRX_STAT
        from TABLEC c
        where c.CW_TRX_ID = '20150415110000798'
    ) t0
    group by CW_TRX_STAT
) as r /* representative */
    on r.CW_UPD_TMS = d.CW_UPD_TMS and r.CW_TRX_STAT = d.CW_TRX_STAT

【讨论】:

  • 试过你的查询得到这个错误:列名 'CW_UPD_TMS' 在 FROM 列表中的多个表中。我认为当内部加入 r 时会被击中。
  • 这只是意味着您需要在最外面的select 子句中限定该列。我想我原本以为我会写 where in 而不是内部连接...
猜你喜欢
  • 1970-01-01
  • 2015-11-25
  • 1970-01-01
  • 2022-09-27
  • 1970-01-01
  • 1970-01-01
  • 2014-03-11
  • 1970-01-01
  • 2022-01-22
相关资源
最近更新 更多