【问题标题】:Dynamic Schema name in SQL ViewSQL 视图中的动态模式名​​称
【发布时间】:2019-10-21 01:27:56
【问题描述】:

我有两个数据集:

  1. 一个是关于狗的数据 [我的数据]
  2. 第二个是匹配键的查找表 [我无法控制此数据]

匹配的键会定期更新,我想创建 Dog 数据集的视图(或实现相同目的的东西),它总是加入 最新的匹配键。此外,我需要能够内联引用它 - 就好像它是一个表格。

查找表中的匹配更新由它们的架构名称来区分,因此要获取最新的,我只需识别最新的架构名称并将其从查询中换出。

鉴于视图和表值函数都禁止动态 SQL,并且无法像表一样引用存储过程,我如何仅在 SQL 中实现这一点?

【问题讨论】:

  • 您不能在视图中使用动态 SQL,因为视图只能包含 SELECT 语句;毕竟VIEW 只是一个预编译SELECT 语句。这里的问题似乎是您的数据库的设计。为什么每次更新数据时都要创建新对象(架构和表)?
  • 我不是,那是我无法控制的数据库部分。
  • 您可能需要创建一个作业(可能是 SQL 代理)来监视外部更改并在需要时更新视图或将所需数据的副本加载到数据库中。
  • 无论哪种方式,恐怕您都无法使用“仅 SQL”实现您所追求的目标,您必须使用动态 SQL 才能动态查询正确的表。否则,如果不能,理想情况下需要修复数据库的设计。
  • “只是 SQL”是指不必使用另一种编程语言。如果有办法将动态 SQL 与视图或 TableValuedFunctions 集成,那么它会很好,但情况似乎并非如此。

标签: sql sql-server tsql dynamic table-valued-parameters


【解决方案1】:

查找表中的匹配更新由它们的架构名称区分,因此要获取最新的,我只需识别最新的架构名称并将其从查询中换出。

您可以使用视图来解决这个问题,但是每当新数据输入到数据库中时,您都需要某种方式来更改它。

我假设每当创建新架构时,也会在该架构中创建一个新表,但表名和它的列名始终相同。请注意,此假设对于我将要提出的解决方案至关重要 - 该解决方案是使用 DDL 触发器在数据库级别侦听 create_table 事件来更改您的视图,以便它将引用新的架构创建表。

我所做的另一个假设是您已经拥有初始视图,或者您正在使用 SQL Server 2016 或更高版本(允许创建或更改语法)。

首先,让我们创建初始视图:

CREATE VIEW dbo.TheView 
AS 
    SELECT NULL As Test 
GO

然后,我添加了 DML 触发器,它根据新创建的表的架构创建并执行动态 alter view 语句:

CREATE TRIGGER AlterViewWhenSchemaChanges
    ON DATABASE
    FOR CREATE_TABLE
AS

    DECLARE @Sql nvarchar(max),
            @NewTableName sysname,
            @NewSchemaName sysname;

    SELECT  @NewSchemaName = EVENTDATA().value('(/EVENT_INSTANCE/SchemaName)[1]',  'NVARCHAR(255)'),
            @NewTableName = EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]',  'NVARCHAR(255)');

    -- We only want to alter the view when this specific table is created!
    IF @NewTableName = 'TableName' 
    BEGIN 

        SELECT @Sql = 
        'ALTER VIEW dbo.TheView
        AS
            SELECT Col as test
            FROM '+ @NewSchemaName +'.'+ @NewTableName

        EXEC(@Sql)
    END
GO

这样,每当创建具有特定名称(在我的示例中为TableName)的新表时,视图就会更改为引用最后创建的TableName(显然是在最新架构中创建的)。

测试脚本:

SELECT * FROM dbo.TheView;
GO

结果:

Test
NULL

使用表 TableName 创建一个新架构

CREATE SCHEMA SchemaName
CREATE TABLE SchemaName.TableName (Col int);

GO  

-- insert some data
INSERT INTO SchemaName.TableName(Col) VALUES (123);

-- get the data from the altered view
SELECT * FROM dbo.TheView

结果:

test
123

You can see a live demo on Rextester.

【讨论】:

    猜你喜欢
    • 2014-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多