【问题标题】:Using human-readable constants in queries在查询中使用人类可读的常量
【发布时间】:2014-02-19 13:46:37
【问题描述】:

这是一个示例查询:

SELECT thing_id
FROM thing
WHERE thing_type IN (3, 7)

我想将 3 和 7 转换为人类可读的名称,以帮助理解查询的真正作用。像下面这样的东西会很棒:

SELECT thing_id
FROM thing
WHERE thing_type_id IN (OPENED, ONHOLD)

知道 OPENED 和 ONHOLD 会在其他地方声明它们的实际值。

我在想可能还有一种方法可以通过 JOIN 的 thing_type 表来做到这一点。

请注意,我被困在直接编写查询代码而不是使用抽象框架的环境中。

【问题讨论】:

  • 一定要看看我的回答。得票最多的是在正确的轨道上,但不提倡重复使用。

标签: sql oracle


【解决方案1】:

假设您有一个名为 ThingNames 的链接表,其中有两列 id 和 ThingName,您可以这样做

SELECT thing_id

FROM thing

LEFT JOIN ThingNames on thing.thing_type_id = ThingName.id

WHERE ThingNames.ThingName IN ('OPENED', 'ONHOLD')

(不要忘记括号中 ThingNames 周围的引号。

【讨论】:

  • P.S 如果还不是很明显,您需要使用所有不同事物的 id 和名称填充 ThingNames 表(每个只有一行),并确保 thing_id 在您的事物中table 等于 ThingName 中的 id。
  • 好的,由于 where 条件 ThingName 永远不会是 NULL,但在这里使用 INNER JOIN 是否更合适?
  • 也许可以,但是对于您提出的原始问题,尽管给出了 where 子句,但左连接很好。为进步干杯。
  • 看起来像我的想法,使用文本 ID 指向特定条目并在后台留下数字 ID 以进行实际连接。无论如何,这是一种最佳做法,还是这种方法有缺点?
  • Leokhorn - 通常是的,这是标准的关系数据库设计最佳实践:对于除了最小的数据库之外的所有数据库,它将节省您在您的数据库中存储大量重复文本(这对性能非常不利)主要数据表。针对不同情况(内部、左侧、外部等)有不同类型的连接,但这超出了本问题的范围
【解决方案2】:

您可以通过为值生成查找表来做到这一点:

with Lookup(value, name) as (
      select 3, 'OPENED' from dual union all
      select 7, 'ONHOLD' from dual
     )
SELECT thing_id
FROM thing t
WHERE thing_type_id IN (select value from Lookup where name in ('OPENED', 'ONHOLD'));

我会推荐这样的方法。但你也可以这样做:

with thevalues as (
      select 3 as OPENED, 7 as ONHOLD from dual
     )
SELECT thing_id
FROM thing cross join
     thevalues
WHERE thing_type_id IN (OPENED, ONHOLD);

这与您的原始查询最相似。

【讨论】:

  • 这似乎很重复,但是如果您在几个不同的查询中需要此逻辑并且我看不到物理查找表的优势?
  • @plalx 。 . .声明中是否有某些内容:“我会推荐这样的方法。但你也可以这样做:”你不明白吗?我提供了第二种方法,因为它看起来更像 OP 原始问题中的常量。
  • 你的两个建议都有相同的缺点......我不明白你的意思吗?
  • 我希望首先在数据库中有查找表,但如果我没有,这将是一个很好的补偿技巧。赞赏。
【解决方案3】:

已经提出了一些解决方案,但是如果您想避免一直加入类型表来获取描述,您可以创建一个 UDF。但是我不确定它会对性能产生什么样的负面影响。

SELECT thing_id
FROM thing
WHERE thing_type_id IN (udf_TypeIdFromCode('OPENED'), udf_TypeIdFromCode('ONHOLD'))

你也可以让类型代码成为视图的一部分,这样你就可以做到:

SELECT thing_id
FROM vThing
WHERE thing_type_code IN ('OPENED', 'ONHOLD')

或者,如果它有意义并适用于您的域,您也可以将字符串代码设为 id 本身。我自己从来没有真正做过,总是喜欢一个独特的受限附加code 列,但我想这可能是一个可行的解决方案。

但是,为此目的使用额外的code 列的好处是,您可以只为查询中实际需要引用的类型提供代码,从而消除了为不需要的类型查找代码的负担。

【讨论】:

  • 使用代码列作为主键让我想知道性能影响。我一直看到数字 ID 用作主键,所以我猜这是有原因的。视图的想法是一个很好的想法。
【解决方案4】:

我假设 OPENED 和 ONHOLD 是字符串,而不是查询中的列。

可以做到这一点;如果您的数据库是关系数据库,thing_type 列应该有一个指向另一个表的外键,该表将具有这些值。因此,您的查询变为:

select thing_id
  from thing t
  join thing_types tt
    on t.thing_type_id = tt.id
 where tt.description in ('OPENED', 'ONHOLD')

可以通过查询USER_CONSTRAINTS查看是否有外键。

select *
  from user_constraints
 where table_name = 'THING'

【讨论】:

  • OPENED 和 ONHOLD 应该 是完美世界中的字符串,但我看到表中的“类型”列只有数字,没有字符串列或查找表视线,也许只是一个字段注释,让您知道这些数字的含义。
  • 我没有看到类型列的问题,只有数字(只要有外键)。我指的是您没有在问题中将它们括在引号中,这意味着它们是列而不是字符串。
  • 我的意思是,当然,没有外键...只有数字,与某个地方的开发人员头脑中的抽象定义无关。至于我的语法,我使用了 Java 的约定,其中常量全部大写。 OPENED 将是一个包含数值的变量。
【解决方案5】:

另一种不使用 in 加入的方法,我认为这会运行得更快,但您可以根据您的真实数据进行测试。

假设您有一个名为 ThingNames 的链接表,其中有两列 id 和 ThingName,您可以这样做

SELECT thing_id
FROM thing
where thing.thing_type_id in (select ThingName.id from ThingName WHERE ThingNames.ThingName IN ('OPENED', 'ONHOLD'))

从 Diamond Fox 的答案复制的表和列名称

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-02
    • 2016-01-08
    • 1970-01-01
    • 1970-01-01
    • 2010-12-27
    • 2011-09-14
    相关资源
    最近更新 更多