【问题标题】:Oracle - Return shortest string value in a set of rowsOracle - 返回一组行中的最短字符串值
【发布时间】:2010-04-20 16:14:49
【问题描述】:

我正在尝试编写一个返回列中最短字符串值的查询。例如:如果 ColumnA 具有值 ABCDE、ZXDR、ERC,则查询应返回“ERC”。我已经编写了以下查询,但我想知道是否有更好的方法来做到这一点?

查询应该返回一个值。

select distinct ColumnA from
(
  select ColumnA, rank() over (order by length(ColumnA), ColumnA) len_rank 
    from TableA where ColumnB = 'XXX'
)
where len_rank <= 1

【问题讨论】:

    标签: sql oracle plsql


    【解决方案1】:

    怎么样:

    select ColumnA
    from
    (
      select ColumnA
      from tablea
      order by length(ColumnA) ASC
    )
    where rownum = 1
    

    【讨论】:

    • 而且,为了提高此查询的性能,您可以在 LENGTH(ColumnA) 上添加基于函数的索引。
    • 我认为您应该在这里删除“DESC”关键字。
    • 我同意 - Jeffrey 错误地编辑了帖子;我会更正
    • for sql server 使用这个>> order by len(ColumnA) ASC
    【解决方案2】:

    这将帮助您获取列中长度最小的所有字符串。

    select ColumnA 
    from TableA 
    where length(ColumnA) = (select min(length(ColumnA)) from TableA)
    

    希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      最简单的方法,单表访问,没有子查询:

      SQL> create table mytable (txt)
        2  as
        3  select 'ABCDE' from dual union all
        4  select 'ZXDR' from dual union all
        5  select 'ERC' from dual
        6  /
      
      Table created.
      
      SQL> set autotrace on explain
      SQL> select min(txt) keep (dense_rank first order by length(txt)) txt
        2    from mytable
        3  /
      
      TXT
      -----
      ERC
      
      1 row selected.
      
      
      Execution Plan
      ----------------------------------------------------------
         0      SELECT STATEMENT Optimizer=CHOOSE
         1    0   SORT (AGGREGATE)
         2    1     TABLE ACCESS (FULL) OF 'MYTABLE'
      

      编辑:我调整了示例以更适合您的示例查询:

      SQL> create table tablea (columna,columnb)
        2  as
        3  select 'ABCDE', 'XXX' from dual union all
        4  select 'ZXDR', 'XXX' from dual union all
        5  select 'ERC', 'XXX' from dual
        6  /
      
      Table created.
      
      SQL> set autotrace on explain
      SQL> select min(columna) keep (dense_rank first order by length(columna)) columna
        2    from tablea
        3   where columnb = 'XXX'
        4  /
      
      COLUM
      -----
      ERC
      
      1 row selected.
      
      
      Execution Plan
      ----------------------------------------------------------
         0      SELECT STATEMENT Optimizer=CHOOSE
         1    0   SORT (AGGREGATE)
         2    1     TABLE ACCESS (FULL) OF 'TABLEA'
      

      问候, 抢。

      【讨论】:

      • 不错的简单解决方案,具有完整且格式良好的测试用例,包括示例数据。
      【解决方案4】:

      这个问题有两个部分。另一种确定最短字符串的方法是老式的子查询:

      select distinct ColumnA 
      from tablea 
      where length(ColumnA) = ( select min(length(ColumnA)) 
                                from TableA 
                                where ColumnB = 'XXX'
                              )
      /
      

      哪个更好?这取决于索引、数据量等,但我猜你的版本可能会表现得更好。除非您在外部查询中复制了 where ColumnB = 'XXX',否则它也可能会给出稍微不同的结果。

      与您的解决方案一样,此查询将为 ColumnA 的每个值返回一行,该值长为三个字符。如果您想返回单行,可以通过使用rownum 限制它来实现。如果您想应用一些标准来确定哪一行是您需要将其嵌入到进一步的外部查询中的第一行(使用我的查询,但您的查询也可以使用)...

      select * from (
          select ColumnA 
          from tablea 
          where length(ColumnA) = ( select min(length(ColumnA)) 
                                    from TableA 
                                    where ColumnB = 'XXX'
                                  )
          order by ColumnA
          ) 
      where rownum = 1
      /
      

      【讨论】:

      • 我认为您不需要在第二个示例中嵌套查询以限制为单行。
      • @mmark - 公平点,我已经修改了文本和示例,所以两者都同意
      【解决方案5】:

      稍微扩展 APC 的答案,我认为这会稍微好一点:

      SELECT DISTINCT columna
        FROM tablea t1
       WHERE EXISTS ( SELECT 1 FROM tablea t2
                       WHERE LENGTH(t2.columna) = MIN(LENGTH(t1.columna)) )
         AND rownum = 1
      

      IIRC,APC 的子选择将为 tablea 中的每一行运行一次。我相信这不会。

      请注意,如果您在 columna 中有多个具有相同长度字符串的行,则多次运行此查询可能无法获得一致的结果。

      【讨论】:

        【解决方案6】:

        我知道这个答案很长而且很老。 但我想我知道另一种好方法。

        因为所有答案都使用子查询,所以不适合我的情况。 于是我找到了一种不使用子查询的方式。

        假设我有如下数据。

        select  *
        from    (select 'x' f  from dual union all select 'aaaaa' from dual) a
        

        --输出

        x
        aaaaa
        

        如果我选择最小值,它会返回“aaaaa”,因为“a”按 ascii 顺序小于“x”。

        select  min(a.f)
        from    (select 'x' f  from dual union all select 'aaaaa' from dual) a
        

        --输出

        aaaaa
        

        但如果我选择最小长度,它会返回 1(代表“x”值),因为 1 按数字顺序小于 5。

        select  min(length(a.f))
        from    (select 'x' f  from dual union all select 'aaaaa' from dual) a
        

        --输出

        1
        

        如果我选择最小长度转换为填充值也返回'0000000001'(这是'x'值)因为'0000000001'更小 比 '0000000005' 按 ascii 顺序排列。

        select  min(lpad(length(a.f), 10, '0'))
        from    (select 'x' f  from dual union all select 'aaaaa' from dual) a
        

        --输出

        0000000001
        

        我可以将它与值本身绑定。

        select  lpad(length(a.f), 10, '0') || a.f
        from    (select 'x' f  from dual union all select 'aaaaa' from dual) a
        

        --输出

        0000000001x
        0000000005aaaaa
        

        现在我可以同时选择长度和值的最小值。

        select  min(lpad(length(a.f), 10, '0') || a.f)
        from    (select 'x' f  from dual union all select 'aaaaa' from dual) a
        

        --输出

        0000000001x
        

        现在我只能通过使用 substr 来获得价值。

        select  substr(min(lpad(length(a.f), 10, '0') || a.f), 11, 999)
        from    (select 'x' f  from dual union all select 'aaaaa' from dual) a
        

        --输出

        x
        

        【讨论】:

          【解决方案7】:
           select city,length(city) from (select city from station ORDER BY length(city) 
           ASC, CITY ASC)where rownum=1;
          
          
           select city,length(city) from (select city from station ORDER BY length(city) 
           DESC, CITY ASC)where rownum=1;
          

          【讨论】:

          • 请在您的回答中添加一些文字说明
          猜你喜欢
          • 2014-12-17
          • 1970-01-01
          • 2013-07-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多