【问题标题】:SQL Creating multiple columns in View from one single table-columnSQL 从一个表列在视图中创建多个列
【发布时间】:2013-06-23 16:44:08
【问题描述】:

我正在尝试在 SQL Server 2008 R2 中创建一个视图,其中数据是从具有双重一对一关系的两个表中提取的,并且我想在基于视图的值中创建两列其中一张桌子。

这些表格目前类似于以下示例:

表A:

PrimaryKey | Name   | Value_FK | Number_FK
-------------------------------------------
66         | NameA  | 1         | 2
77         | NameB  | 3         | 4

表B:

PrimaryKey | Value   
-------------------
1          | 238
2          | 456
3          | 100
4          | 200

视图应如下所示:

 Name   | Value | Number
-------------------------
 NameA  | 238   | 456
 NameB  | 100   | 200

('Value'和'Number'本质上是同一类型,都在TableB的'Value'列中。我认为区分'Value'和'Number'比'值A'和'值B')。

应该决定哪些值进入“值”列或“数字”列的因素是 TableB 中的 PrimaryKey 及其在 TableA 中的任一外键中的引用(但两个 FK 不得引用相同的键)。

这可能不是最出色的数据库模型,在表之间具有双重关系。然而,这是由于使用 ADO.NET Entity Framework 将一些 C#.NET 类映射到数据库,其中 A 类有 B 类的两个对象(在本例中名为“值”和“数字”),以及当前的数据库模型因此构建了两个关系。改变这不是一种选择。

我试过用谷歌搜索这个,但我发现很难找到我需要的答案。尤其是当大多数结果正好相反时:将多列选择为一列。

那么,Select语句应该怎么写呢?

CREATE VIEW ViewName
AS
SELECT DISTINCT a.Name as 'Name', ????? as 'Value', ????? as 'Number'
FROM TableA a, TableB b

我对高级 SQL 命令很生疏。自从上次我进入这么先进的东西以来,已经过去了 1.5 年。我首先尝试了类似的方法:

CREATE VIEW ViewName
AS
WITH Name AS
( SELECT DISTINCT a.Name FROM TableA a  )

Value AS
(
    SELECT DISTINCT b.Value as 'Value' FROM TableA a, TableB b
WHERE b.PrimaryKey = an.ValueA_FK
),
Number AS
(
    SELECT DISTINCT b.Value  as 'Number'
    FROM TableA a, TableB b
    WHERE a.PrimaryKey = an.ValueB_PrimaryKey
)
SELECT DISTINCT 
    * FROM Name, Value, Number

我完全失败的尝试的结果是这样的:

 Name   | Value | Number
-------------------------
 NameA  | 100   | 200
 NameB  | 100   | 200
 NameA  | 100   | 456
 NameB  | 100   | 456
 NameA  | 238   | 200
 NameB  | 238   | 200
 NameA  | 238   | 456
 NameB  | 238   | 456

现在,有什么建议可以填写查询吗?

【问题讨论】:

  • 首先不要使用隐式连接,它们是 SQL 反模式。随着时间的推移,它们更容易磨损并且更难维护。它们也已经过时了 20 多年。

标签: sql sql-server-2008 database-design view


【解决方案1】:

您可以在FROM 子句中多次引用同一个表:

SELECT a.Name as 'Name', b1.Value as 'Value', b2.Value as 'Number'
FROM TableA a
  inner join TableB b1
          on
                a.Value_FK = b1.PrimaryKey
  inner join TableB b2
          on
                a.Number_FK = b2.PrimaryKey

我还删除了DISTINCT,因为添加一个不应该是您的习惯,而且问题中没有任何内容表明需要添加一个。我还使用了 ANSI 样式的连接。这些几乎总是比旧样式更受欢迎(FROM 子句中的表格只是用逗号分隔)


如果TableA 中的某些行可能有NULL Value_FKNumber_FK,并且您仍然希望这些行出现在您的视图中,您可以将inner joins 中的一个或两个切换为left joins。然后,您还将决定输出列是应该是 NULL(在这种情况下您已经完成)还是其他一些值(在这种情况下,您将拥有例如 COALESCE(b1.Value,<Value when null>) as 'Value')。

【讨论】:

  • 在这种情况下,您必须多次引用该表。您可能需要左连接(并且通常在这种类型的结构中使用,因为不能保证任何一种数据类型的相关记录)。这就是为什么表设计的 EAV 模型很受欢迎的原因之一。如果您在那里存储了 6 种不同类型的值,则需要 6 个连接。如果您不知道您将拥有多少,您将被困在动态创建查询中(当然您不能为视图执行此操作)。
  • @HLGEM - 你没有 - 你可以使用基于 OR 的谓词加入它一次,然后使用 MAX(CASE ... 进行伪枢轴然后将不同的连接条件拆分到各自的列中。不过,这不是我推荐的方法。你可能想要LEFT JOINs 可能是正确的,但如果这是一个要求,OP 没有指出它。
  • 我刚刚提出左连接是因为它可能需要考虑,而不是因为我认为您的代码有误。
【解决方案2】:

这个查询会产生你想要的结果:

select t1.Name, value.Value, number.Value as Number
from TableA t1
inner join TableB value on value.PrimaryKey = t1.Value_FK
inner join TableB number on number.PrimaryKey = t1.Number_FK

你的查询过于复杂了。

【讨论】:

  • 可能过于复杂,但这是一个伪代码,仅显示问题的相关数据。真正的查询要大得多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-09
  • 1970-01-01
  • 2017-03-30
  • 2020-09-04
  • 1970-01-01
  • 2020-03-14
相关资源
最近更新 更多