2009-04-23 3 views
0

У меня возникли проблемы с записью запроса. У меня есть поддержка, называемая «MYTABLE», и у нее есть столбец «TABLENAME», который может содержать одно или несколько имен таблиц. Несколько таблиц разделяются запятыми.Ошибка написания SQL-запроса

Пример:

TBLUSER 
TBLUSER, TBLACCOUNT 

Я пытаюсь написать запрос, который будет идентифицировать все записи в таблице MyTable, которые не являются допустимыми таблицами в базе данных. Я был в состоянии написать последующих ....

     SELECT * 
         FROM MYTABLE T1 
      LEFT outer JOIN ALL_TAB_COLS T2 
         ON ( upper(T1.TABLENAME) = upper(t2.Table_Name) 
          AND T2.Owner = 'ME' 
          ) 
         WHERE TABLE_NAME IS NULL; 

И это работает точно так же, как я хочу - но это работает только тогда, когда запись в MYTABLE содержит одну таблицу. Когда есть несколько таблиц, разделенных запятыми - это терпит неудачу. Мои навыки SQL немного отсутствуют, и мой естественный инстинкт - «Делать для каждого», но я считаю, что это неправильный подход (и я не знаю, как это сделать в SQL).

+0

Почему в мире вы бы сохранили несколько таблиц в одной строке? – TheTXI

+0

Обратная нормализация, TheTXI. Это ярость. – Welbog

+0

Я считаю, что первоначальная мысль заключалась в том, что пользователям «нетехнических» было бы легче модифицировать данные, если бы они могли просто ввести все в одном поле. Я не уверен, согласен ли я с этим или нет; но, к сожалению, это «как это». Естественно, когда одна из этих таблиц ошибочна, это приводит к сбою приложения - я надеялся написать SQL-запрос, чтобы идентифицировать строки, которые приведут к сбою. –

ответ

2

Вы храните строку в MYTABLE.TABLENAME и пытаетесь сопоставить ее со строкой в ​​ALL_TAB_COLS.TABLE_NAME (что, кстати, я не вижу причин, по которым вы бы использовали ALL_TAB_COLS вместо ALL_TABLES в этом случае).

Если ваша строка «TBLUSER, TBLACCOUNT», она не будет равна строке «TBLUSER» или строке «TBLACCOUNT». Это все выражение upper(T1.TABLENAME) = upper(t2.Table_Name) тестирует - эти две строки равны? Вы, кажется, ожидаете, что он каким-то образом «знает», что ваши данные являются списком имен таблиц, разделенных запятыми.

Метод грубой силы, чтобы сделать то, что вы работаете, используя сравнения строк, заключается в изменении условия на ','||upper(T1.TABLENAME)||',' LIKE '%,'||upper(t2.Table_Name)||',%. Таким образом, вы в основном будете смотреть, является ли TABLE_NAME подстрокой столбца TABLENAME.

Однако реальная точка зрения заключается в том, что это не очень хороший дизайн базы данных. Прежде всего, из простой точки ясности, почему вы бы назвали столбец «TABLENAME» (единственное), а затем поместили в него значения, которые представляют собой несколько имен таблиц? Если вы собираетесь это сделать, вы должны хотя бы называть его чем-то вроде «TABLENAMELIST».

Что еще более важно, это не так, как мы делаем вещи в реляционных базах данных.Если ваш MYTABLE выглядит следующим образом:

ID  TABLENAME 
1  TBLUSER 
2  TBLUSER, TBLACCOUNT 

то более правильный реляционный способ разработки таблицы будет:

ID  TBL_NUM TABLENAME 
1  1   TBLUSER 
2  1   TBLUSER 
2  2   TBLACCOUNT 

Тогда ваш запрос будет работать как есть, более или менее, потому что TABLENAME столбец всегда будет содержать имя одной таблицы.

3

Вам действительно нужно переосмыслить свой проект базы данных. Сохранение нескольких записей в одной записи в таблице, которая должна отслеживать эти записи, - большой гигантский WTF.

Вы должны изменить свой дизайн таким образом, что вместо того, что вы описали вас есть что-то вроде:

ID TABLENAME 
---------------------- 
1  TBLUSER 
2  TBLUSER 
2  TBLACCOUNT 

Где ID + TABLENAME является составной первичный ключ. Это сделало бы ваш запрос, на который вы написали работу (хотя и не работа, основанная на приведенном выше примере bare-bones).

ПРИМЕЧАНИЕ Я знаю, что это может быть и не то, что вы ищете в своей конкретной проблеме, но я считаю, что так или иначе важно, потому что будущие пользователи могут прийти и найти эту проблему и нуждаются в лучшем понимании нормализации базы данных (которые вы, возможно, не сможете сделать, поскольку приложение так же, как и потому, что «так оно и есть»).

+0

Это отличный момент. Согласовано. –

1

Короткий ответ:

select distinct 
    atc.table_name 
from 
    mytable mt 
,all_tab_cols atc 
where atc.owner = 'SOMESCHEMA' 
    and (
     mt.tablename = atc.table_name 
     or 
     (
     0 < instr(','||replace(upper(mt.tablename),' ','')||',' 
          ,','||upper(atc.table_name)||',') 
     ) 
    ) 

Длинный ответ был уже хорошо описывается пост Дэвида Косты.

Смежные вопросы