什么是Oracle中mysql的Find_in_set的替代方案

时间:2015-03-09 13:00:00

标签: oracle

select   CASE
          WHEN ComExgRateDetailLog.NotificationMinute = '*'
          THEN
             1
          ELSE
             IF(FIND_IN_SET(
                   CAST(
                      DATE_FORMAT(
                         DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:00'),
                         '%i') AS SIGNED),
                   ComExgRateDetailLog.NotificationMinute) > 0,
                1,
                0)
       END

       From ComExgRateDetailLog

我在oracle中想要相同的结果。在oracle中设置find_in的替代选项是什么?

此处ComExgRateDetailLog.NotificationMinute包含类似'0,15,30,45'的值,因此查询应该像

select   CASE
          WHEN ComExgRateDetailLog.NotificationMinute = '*'
          THEN
             1
          ELSE
             IF(FIND_IN_SET(
                   CAST(
                      DATE_FORMAT(
                         DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:00'),
                         '%i') AS SIGNED),
                   '0,15,20,45') > 0,
                1,
                0)
       END

       From ComExgRateDetailLog

3 个答案:

答案 0 :(得分:3)

不是MySQL FIND_IN_SET的精确替代品,但在您的示例中(您只需要知道如果一个值包含在以逗号分隔的集合中)Oracle的REGEX_COUNT { 3}}正则表达式'^([^,]+,)*your_value(,[^,]+)*$'适合。

检查以下SQL查询(对于Oracle)...

数字

的例子

在集合中搜索号码1[1,2,3,4,5,6,11,12,13]

SELECT
    CASE WHEN REGEXP_COUNT('1,2,3,4,5,6,11,12,13', '^([^,]+,)*1(,[^,]+)*$', 1, 'i') > 0
        THEN 1 ELSE 0
    END AS cnt
FROM DUAL;

正确退回 1

在集合中搜索数字1:[111,222,333]。在这种情况下,INSTR将不会报告否定。

SELECT
    CASE WHEN REGEXP_COUNT('111,222,333', '^([^,]+,)*1(,[^,]+)*$', 1, 'i') > 0
        THEN 1 ELSE 0
    END AS cnt
FROM DUAL;

正确退回 0

字符串示例

在一组名称中搜索'John'

SELECT
    CASE WHEN REGEXP_COUNT('john,peter,jim,kelly,laura,bill,tom,foo,bar', '^([^,]+,)*John(,[^,]+)*$', 1, 'i') > 0
        THEN 1 ELSE 0
    END as cnt
FROM DUAL;

正确退回 1

  

如果您需要区分大小写的搜索,请根据documentation'i'的最后一个REGEXP_COUNT参数替换为'c'

但是如果你搜索字母'a',它将正确返回零(INSTR会再次失败)。

SELECT
    CASE WHEN REGEXP_COUNT('john,peter,jim,kelly,laura,bill,tom,foo,bar', '^([^,]+,)*a(,[^,]+)*$', 1, 'i') > 0
        THEN 1 ELSE 0
    END as cnt
FROM DUAL;

正确退回 0

我知道这个问题很久以前就得到了解答,但它在搜索结果中排名很好,可能会帮助其他人寻找一个比Oracle INSTR函数更简单但更正确的解决方案。< / p>

布尔表达式

也可以使用布尔表达式,如ORAND

使用OR的示例如下:

SELECT
    CASE WHEN REGEXP_COUNT('john,peter,jim,kelly,laura,bill,tom,foo,bar', '^([^,]+,)*(helen|peter)(,[^,]+)*$', 1, 'i') > 0
        THEN 1 ELSE 0
    END as cnt
FROM DUAL;

正确地返回 1 ,因为它找到了&#34; peter&#34; (搜索&#34; helen&#34; &#34; peter&#34; )。

对于AND,方法略有不同(修改 CASE表达式而不是正则表达式):

SELECT
    CASE WHEN
            REGEXP_COUNT('john,peter,jim,kelly,laura,bill,tom,foo,bar', '^([^,]+,)*john(,[^,]+)*$', 1, 'i') > 0 AND
            REGEXP_COUNT('john,peter,jim,kelly,laura,bill,tom,foo,bar', '^([^,]+,)*peter(,[^,]+)*$', 1, 'i') > 0
        THEN 1 ELSE 0
    END as cnt
FROM DUAL;

上述查询会搜索&#34; john&#34; AND &#34; peter&#34; 。通过复制AND语法中的REGEXP_COUNT表达式,可以轻松实现CASE操作,但是性能损失很小。

答案 1 :(得分:2)

select FIND_IN_SET('15', '0,15,20,45') from dual would return 2

为了在oracle中实现这一点,请使用INSTR函数,但INSTR与FIND_IN_SET并不完全相同。 INSTR将逗号,空格,字符串中的任何内容视为字符。

SELECT INSTR ('0,15,20,45', '15',1,1) FROM dual would return 3

您可以阅读INSTR here

答案 2 :(得分:2)

CREATE OR REPLACE FUNCTION find_in_set(
  i_value  IN  VARCHAR2,
  i_list   IN  VARCHAR2,
  i_delim  IN  VARCHAR2 DEFAULT ','
) RETURN INT DETERMINISTIC
AS
  p_result       INT       := 0;
  p_start        NUMBER(5) := 1;
  p_end          NUMBER(5);
  c_len CONSTANT NUMBER(5) := LENGTH( i_list );
  c_ld  CONSTANT NUMBER(5) := LENGTH( i_delim );
BEGIN
  IF c_len > 0 THEN
    p_end := INSTR( i_list, i_delim, p_start );
    WHILE p_end > 0 LOOP
      p_result := p_result + 1;
      IF ( SUBSTR( i_list, p_start, p_end - p_start ) = i_value )
      THEN
        RETURN p_result;
      END IF;
      p_start := p_end + c_ld;
      p_end := INSTR( i_list, i_delim, p_start );
    END LOOP;
    IF p_start <= c_len + 1
       AND SUBSTR( i_list, p_start, c_len - p_start + 1 ) = i_value
    THEN
      RETURN p_result + 1;
    END IF;
  END IF;
  RETURN 0;
END;
/