Oracle - 返回一组行中的最短字符串值

Posted

技术标签:

【中文标题】Oracle - 返回一组行中的最短字符串值【英文标题】:Oracle - Return shortest string value in a set of rows 【发布时间】: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

【问题讨论】:

【参考方案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;

【讨论】:

请在您的回答中添加一些文字说明

以上是关于Oracle - 返回一组行中的最短字符串值的主要内容,如果未能解决你的问题,请参考以下文章

如何确定一个值是不是在使用 Dplyr 的一组行中出现最多? [复制]

查询与 Hive QL 中另一列中的每个值关联的最短字符串值的更有效方法

Oracle SQL - 过滤掉包含具有特定值的行的分区或行组

如何使用分析窗口 SQL 函数在同一数据集的多组行中查找 id 值

按行数聚合值

Oracle pl sql 10g - 将一组行从表移动到具有相同结构的历史表