Получение всех возможных значений, которые не находятся в одном столбце, но с указанными условиями - PullRequest
1 голос
/ 24 мая 2019

Я пытаюсь получить все значения из таблицы с такими условиями:

  • длина значения 3
  • значение не в значениях, которые больше, чем 3

Пример таблицы (simple_table):

id | name
-------------
1  | 418
2  | 223:542
3  | 54
4  | 418
5  | 418:223:100
6  | 223
7  | 999
8  | 132
9  | null
10 | 100

Итак, у меня три разных класса длины

  • длина имени 3
  • длина имени меньше 3
  • длина имени более 3

Мой код:

Первый

select distinct name 
from simple_table
where name is not null  
and LENGTH( name ) = 3;

Возвращаемые значения

name
-------
418
223
999
132

Второе:

select distinct name 
from simple_table
where name is not null  
and LENGTH( name ) > 3;

Возвращаемые значения

name
-------
223:542
418:223:100

«Основная часть» кода

select distinct name 
from simple_table
where name is not null  
and LENGTH( name ) = 3
and '223:542' not like CONCAT(CONCAT('%', name ), '%');

Это возвращение

name
-------
418
999
132
100

Когда я пытаюсь использовать этот код, он вызывает ошибку

select distinct name
from simple_table
where name is not null  
and LENGTH( name) = 3
and (select distinct name
from simple_table
where name is not null
and LENGTH( name) > 3) not like in (CONCAT(CONCAT('%', name), '%'));

Ошибка:

ORA-00936: missing expression
00936. 00000 -  "missing expression"
*Cause:    
*Action:
Error at Line: 15 Column: 50

Мой желаемый результат:

name
-------
999
132

Ответы [ 3 ]

2 голосов
/ 24 мая 2019

Следуя инструкциям в теме, которую я упоминал в комментариях, у меня есть следующее решение:

SELECT t1.name 
FROM myTable t1
WHERE LENGTH(name) = 3
AND t1.name NOT IN (
     SELECT DISTINCT REGEXP_SUBSTR(t2.name, '[^:]+', 1, LEVEL) AS data
     FROM myTable t2
     WHERE LENGTH(t2.name) > 3
     CONNECT BY REGEXP_SUBSTR(t2.name, '[^:]+', 1, LEVEL) IS NOT NULL
);

Вот демонстрация этого в действии: SQLFiddle

2 голосов
/ 24 мая 2019

Что вам нужно сделать, это сделать подзапрос EXIST, чтобы отфильтровать вещи, перечисленные в длинных строках, и выполнить сопоставление строк в сочетании с разделителем для этого подзапроса.

SELECT distinct name
FROM   simple_table t1
WHERE  name IS NOT null  
  AND LENGTH(name) = 3
 AND NOT EXISTS (
    SELECT 1
    FROM   simple_table t2
    WHERE  (    t2.name LIKE '%' || ':' || t1.name || '%'  
            OR  t2.name LIKE '%' || t1.name || ':' || '%'  
           )
)

Обратите внимание, что это не совсем без ошибок - например, это будет соответствовать "22" к "222: 3333". Если вы хотите быть более точным, вам нужно изменить запрос на что-то вроде "%:X:%" OR "%:X" OR "X:%"

Вот настройки:

CREATE TABLE simple_table (  
  name VARCHAR2(20) NULL
);

INSERT INTO simple_table VALUES ('222');
INSERT INTO simple_table VALUES ('123');
INSERT INTO simple_table VALUES ('334');
INSERT INTO simple_table VALUES ('001');
INSERT INTO simple_table VALUES ('002');
INSERT INTO simple_table VALUES ('334:555');
INSERT INTO simple_table VALUES ('334:001');
INSERT INTO simple_table VALUES ('777:002');

И результат (из SQL Fiddle http://sqlfiddle.com/#!4/5f88f/16)

222
123
1 голос
/ 24 мая 2019

Используйте not exists, но я бы сказал так:

SELECT DISTINCT st.name
FROM simple_table st
WHERE LENGTH(st.name) = 3 AND
      NOT EXISTS (SELECT 1
                  FROM simple_table st2
                  WHERE LENGTH(st2.name) > 3 AND
                        ':' || st2.name || ':' LIKE ':%' || st.name || ':%'
                 );

Добавляя разделитель в начало и конец строки, вы учитываете имена в начале и конце более длинной строки.

...