编写 SQL 查询时遇到问题

Posted

技术标签:

【中文标题】编写 SQL 查询时遇到问题【英文标题】:Trouble Writing SQL Query 【发布时间】:2009-04-23 19:54:50 【问题描述】:

我在编写查询时遇到问题。我有一个名为“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 中做到这一点)。

【问题讨论】:

到底为什么要在一行中保留多个表? 反向归一化,TheTXI。风靡一时。 我相信它背后的最初想法是,如果“非技术”用户可以在一个字段中全部输入数据,他们会更容易修改数据。我不确定我是否同意;但是,可悲的是,这就是“它是怎样的”。自然,当其中一个表输入错误时,它会导致应用程序崩溃——我希望编写一个 SQL 查询来识别会导致崩溃的行。 【参考方案1】:

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

你需要改变你的设计,这样你的描述就不是这样了:

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

其中 ID + Tablename 是复合主键。这将使您编写的查询工作(尽管根据我上面提供的基本示例无法工作)。

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

【讨论】:

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

简短的回答是:

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 的帖子已经很好地描述了长长的答案。

【讨论】:

以上是关于编写 SQL 查询时遇到问题的主要内容,如果未能解决你的问题,请参考以下文章

编写sql查询的问题

在编写查询 laravel 时遇到问题

编写 SQL 查询工作台

制定 sql 查询时遇到问题

在编写具有多个连接的查询时遇到问题

sql加列前缀查询时遇到一个问题