我正在考虑如选项2 here中那样设置配置表,其中每个配置选项有一行(或者#34;事实"),其中包含事实的名称和事实的价值。
将此信息合并到另一个具有一个或多个连接的查询中的适当/最佳方法是什么?请注意,我明确没有考虑过程SQL或ORM系统;仅限纯SQL。
例如,请考虑这些表格,以设计一个例子:
SELECT tbl_projects.Project_ID, tbl_projects.Name,
(tbl_projects.Revenue - tbl_employees.Salary) AS Gross_Profit
FROM tbl_projects INNER JOIN tbl_employees ON
tbl_projects.Manager_ID = tbl_employees.Employee_ID;
Manager_ID链接到tbl_employees以获取管理项目的员工。每个项目只有一个经理,但员工可以管理多个项目。为了这个例子,Option_Value是数字/双。
忽略项目中其他员工的成本等,让我们找出每个项目的毛利作为收入 - [经理]薪水:
SELECT tbl_projects.Project_ID, tbl_projects.Name,
(tbl_projects.Revenue - tbl_employees.Salary) AS Gross_Profit,
tbl_facts.Option_Value * (tbl_projects.Revenue - tbl_employees.Salary) AS Net_Profit
FROM
(tbl_projects INNER JOIN tbl_employees ON
tbl_projects.Manager_ID = tbl_employees.Employee_ID),
tbl_facts
WHERE tbl_facts.Option_Name="Tax Rate";
够容易。现在让我们说我们知道利润的税率是20%,所以我们将("税率",0.2)存储在tbl_facts(以及其他事实)中。我们想找出净利润。问题是,目前还没有明确的方法将这些信息加入到目前为止。
我见过/考虑的选项:
使用tbl_facts进行笛卡尔/交叉连接。但是,有些SQL不支持这种情况,或者至少不支持它(有时它可以工作,有时它不会)。
SELECT tbl_projects.Project_ID, tbl_projects.Name,
(tbl_projects.Revenue - tbl_employees.Salary) AS Gross_Profit,
cdbl(dlookup("Option_Value","tbl_facts","Option_Name='Tax Rate'")) *
(tbl_projects.Revenue - tbl_employees.Salary) AS Net_Profit
FROM
tbl_projects INNER JOIN tbl_employees ON
tbl_projects.Manager_ID = tbl_employees.Employee_ID;
某些版本的SQL支持查找功能(例如,MS Access< dlookup())。但是,这并不是很好,因为你必须将值转换为你想要的类型,我怀疑它会有性能损失。
SELECT tbl_projects.Project_ID, tbl_projects.Name,
(tbl_projects.Revenue - sq_employees.Salary) AS Gross_Profit,
sq_facts.Option_Value * (tbl_projects.Revenue - sq_employees.Salary) AS Net_Profit
FROM
tbl_projects INNER JOIN
(SELECT 1 AS Join_Col, tbl_employees.* FROM tbl_employees) AS sq_employees ON
tbl_projects.Manager_ID = sq_employees.Employee_ID),
INNER JOIN
(SELECT 1 AS Join_Col, Option_Value FROM tbl_facts WHERE Option_Name="Tax Rate") AS sq_facts ON
sq_employees.Join_Col = sq_facts.Join_Col;
使用子查询添加一个人为的"加入列"。这似乎是一个可怕的选择。
import UIKit
class ViewController: UIViewController {
@IBOutlet var secondView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
print("Main View:")
print("Width: \(self.view.frame.width), Height: \(self.view.frame.height)")
print("Second View:")
print("Width: \(self.secondView.frame.width), Height: \(self.secondView.frame.height)")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
从这样的配置表中获取此信息的首选方法是什么?这是上面的选择之一,还是我还没考虑过的其他选择?
答案 0 :(得分:3)
通常的方法是在SELECT
语句中使用简单的子查询:
SELECT (SELECT TOP 1 Option_Value As Tax_Rate FROM tbl_facts WHERE Option_Name='Tax Rate'), other_columns
FROM tbl_projects
让我们快速回顾一下选项:
所以真正的答案是:它取决于。简单的子查询是最明显的候选者,当您需要多个值时,交叉连接很有用,而DLookUp对于避免使用不可更新的查询时出错很有用。
当然,当我们将VBA引入比较时,它会变得更加复杂。使用VBA的另一种方法是使用一个Options类,它在数据库打开时初始化,并且可以缓存选项查找。
答案 1 :(得分:2)
“你必须将值转换为你想要的类型,我怀疑会有性能损失”
您有一个存储为字符串的数值,并且您希望对其进行算术运算。因此,您必须将其转换为数字:您可以将数据转换显式化,因为您将以任何方式执行此操作。
Oracle确实在预测中支持标量游标。就个人而言,我会在内联视图中以CROSS JOIN的形式进行此操作,在我看来,这是最具表现力的做事方式。您的里程可能会有所不同。
SELECT tbl_projects.Project_ID
, tbl_projects.Name
, (tbl_projects.Revenue - tbl_employees.Salary) AS Gross_Profit
, tf.tax_rate * (tbl_projects.Revenue - tbl_employees.Salary) AS Net_Profit
FROM tbl_projects
INNER JOIN tbl_employees ON
tbl_projects.Manager_ID = tbl_employees.Employee_ID
CROSS JOIN ( select to_number(Option_Value) as tax_rate
from tbl_facts
WHERE Option_Name='Tax Rate') tf
;
如果您要存储键值对,请使用索引组织表。它基本上是一个索引查找,所以为什么要烦扰桌子呢?至少对Oracle而言。 Find out more.
答案 2 :(得分:2)
在开始编写查询之前修复数据模型。将OPTION_VALUE
拆分为多个列,例如OPTION_NUMBER
,OPTION_STRING
和OPTION_DATE
。
永远不要将数据存储在错误的类型中。这是一场等待发生的灾难。名为OPTION_VALUE
的单个列可能看起来像一个简单的解决方案,但您将在以后通过间歇性错误或复杂查询为此付费。
the top answer in the question you referenced建议这样做。我也在this post中写过这篇文章。
总结一下,在EAV模型中使用多个列:
提高类型安全性 - Oracle不必按写入的顺序运行SQL语句。此SQL语句很危险,并且会间歇性地失败:
select *
from
(
select to_number(option_value) tax_rate
from tbl_facts
where option_name='tax rate'
)
where tax_rate >= 1