根据另一个表的值选择表和字段

Posted

技术标签:

【中文标题】根据另一个表的值选择表和字段【英文标题】:Selecting Table and Field based on value of another table 【发布时间】:2015-07-09 12:23:10 【问题描述】:

是否可以从一个表中连接和选择一个字段,其中表和字段名称作为文本存储在另一个表中?

假设我有如下表 TableofValues、TableA、TableB 和 TableC。

是否可以根据TableofValues中的TableName加入相关表,然后根据FieldName选择字段,其中TableRowID = 加入表中的ID?

这是 SQL Server 2008。

示例表集:

期望的结果:

【问题讨论】:

可以,可以动态构造一条SQL语句。但是,只有在您提供更多关于您试图通过这样做实现的目标的信息时,才能提供确切的帮助。 正如@WhirlMind 已经说过的,它肯定会以某种方式按照您建议的方式进行,但也许您应该考虑更改您的表架构,以便所有数据都收集在一个单个表,其中包含一个附加列,将内容标识为属于“tableA”、“tableB”或“tableC”。这样的布局将简化您未来的数据维护。 我第二个之前的语句:重复'TableA','TableB'...并且列名将占用大量数据库空间来提供很少。我已经看到以这种方式链接表,其 'id,table_id,table_row_id,value' 看起来很相似,并且 table_id 指的是另一个描述各种表(名称和列)的表。但是,一些应用程序正在将信息收集到一个表中。请注意,我将使用 INNER JOIN 的 UNION 而不是 LEFT JOIN(或 UNION 的 INNER JOIN)来保持最佳性能。 【参考方案1】:

您也可以在不使用动态查询的情况下实现此目的。见以下代码:

-- Create Demo Data
CREATE TABLE #TableOfValues(id int identity(1,1), value float, TableName nvarchar(30), FieldName nvarchar(30), TableRowId int)

INSERT INTO #TableOfValues(value, TableName, FieldName, TableRowId)
VALUES  (1234.2,N'TableA',N'Customer',1),
        (245.5,N'TableB',N'Cust',3),
        (248.59,N'TableA',N'Customer',2),
        (8526.36,N'TableC',N'Cstmer',1),
        (224.15,N'TableB',N'Cust',5),
        (148.98,N'TableC',N'Cstmer',2)

CREATE TABLE #TableA(id int identity(1,1), Customer nvarchar(30))

INSERT INTO #TableA(Customer) 
VALUES(N'Bloggs'),(N'Smith'),(N'Jones')

CREATE TABLE #TableB(id int identity(1,1), Cust nvarchar(30))

INSERT INTO #TableB(Cust)
VALUES (N'Aother'),(N'NJONES'), (N'FBLOGGS'), (N'SMITH'), (N'BARTHUR')

CREATE TABLE #TableC(id int identity(1,1), Cstmer nvarchar(30))

INSERT INTO #TableC(Cstmer)
VALUES(N'Mr Fred Bloggs'),(N'Tony Smith')

-- Your Part
SELECT tov.id, tov.value, tov.TableName, tov.FieldName, tov.TableRowId, tabs.tabVal
FROM #TableOfValues as tov
INNER JOIN (
    SELECT N'TableA' as tabName, a.id, a.Customer as tabVal
    FROM #TableA as a
    UNION ALL
    SELECT N'TableB' as tabName, b.id, b.Cust as tabVal
    FROM #TableB as b
    UNION ALL
    SELECT N'TableC' as tabName, c.id, c.Cstmer as tabVal
    FROM #TableC as c
) as tabs
    ON tov.TableName = tabs.tabName
    AND tov.TableRowId = tabs.id

-- Cleanup
DROP TABLE #TableOfValues
DROP TABLE #TableA
DROP TABLE #TableB
DROP TABLE #TableC

如果需要,您可以向表中添加(如果它们不存在)索引。如果您寻求特定值,这些将进一步提高查询性能。

CREATE CLUSTERED INDEX [NCI_TableOfValues_id]
ON #TableOfValues ([id])

CREATE CLUSTERED INDEX [NCI_TableA_id]
ON #TableA ([id])

CREATE CLUSTERED INDEX [NCI_TableB_id]
ON #TableB ([id])

CREATE CLUSTERED INDEX [NCI_TableC_id]
ON #TableC ([id])

CREATE NONCLUSTERED INDEX [NCI_TableOfValues_TableName]
ON #TableOfValues([TableName])
INCLUDE ([id],[value],[FieldName],[TableRowId])

除了解决方案之外,桌子设计有点糟糕。它将进一步提高您的SELECT 性能。

【讨论】:

如果需要,您可以使用子选择预过滤行。我已将其更改为 UNION ALL 构造。它在 10 秒内执行。在包含 6.000.000 行的完整结果集上。嗯,我认为它已经足够快了。 :-D 如果您过滤特定的 TableOfValues 值,它将立即出现。 这就是我建议绑定 VIEW 的原因,但是 - 可能 - OP 会对务实的方法感到满意 :-) 我目前会为问题添加一些索引(如果他愿意添加它们)。这可以用来进一步推动它。顺便一提。我同意这个设计很糟糕的观点。但在某些情况下,您只有一个结构,需要以任何方式处理它。 是的,你是对的。在我正在处理的项目中,有几个具有相同方法的通用结构。有时没有办法……我个人最喜欢的是每个特定 TableName 的表值内联函数…… 是的,这也可以是一个解决方案。另一种方法是将表拆分为单个表并为应用程序使用视图。这样您的应用程序将按预期工作,但后台的数据库可以更有效地工作。 ;-)【参考方案2】:

除了你应该有一个非常好的理由之外,因为否则它是非常糟糕的设计,你可以考虑使用 SchemaBinding 的 VIEW。

您必须为任何给定的 TableName 创建一个 VIEW。这可以在 JOIN 中使用

【讨论】:

【参考方案3】:

您也可以这样做。您想要合并来自#TableA#TableB#TableC 的所有行并添加一列以确定FieldName

SELECT
    Customer = FieldValue,
    Value = v.value
FROM #TableOfValues v
LEFT JOIN (
    SELECT id, Customer AS FieldValue, 'Customer' AS FieldName FROM #TableA UNION ALL
    SELECT id, Cust, 'Cust' FROM #TableB UNION ALL
    SELECT id, Cstmer, 'Cst' FROM #TableC
)t
    ON v.FieldName = t.FieldName
    AND v.TableRowId = t.id

【讨论】:

以上是关于根据另一个表的值选择表和字段的主要内容,如果未能解决你的问题,请参考以下文章

ORACLE怎么根据字段值找出所有的表和字段?

怎么根据一个表的字段值修改另一个表的字段值

MySQL:如何根据从另一个表中选择的值填充现有表的新列[关闭]

更新一个表的字段值等于另一个表的字段值的SQL语句

SQL语句 一个表的值与另一个表的字段一致,怎么把两一个表的值作为条件,限定查询的字段

Sql Server 中 根据具体的值 查找该值所在的表和字段