麻烦编写SQL查询

时间:2009-04-23 19:54:50

标签: sql oracle

我在编写查询时遇到问题。我有一个名为'MYTABLE'的支持表,它有一个名为'TABLENAME'的列,其中可以有一个或多个表名。多个表格用逗号分隔。

示例:

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中做到这一点)。

3 个答案:

答案 0 :(得分:3)

您真的需要重新考虑您的数据库设计。在一个应该跟踪这些条目的表中的单个记录上保留多个条目是一个巨大的巨型WTF。

您需要更改您的设计,以便代替您所描述的内容,例如:

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

ID + Tablename是复合主键。这将使您的查询已经编写了工作(虽然不能基于我上面提供的简单示例)。

注意我知道这可能不是您在确切问题中寻找的内容,但我觉得无论如何都要说,因为未来的用户可能会来找到这个问题,需要更好的理解数据库规范化实践(由于应用程序原样,您可能无法做到这一点,因为“它就是这样”)。

答案 1 :(得分: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列始终包含单个表的名称。

答案 2 :(得分: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)||',')
       )
      )

David Costa的帖子已经很好地描述了很长的答案。