【问题标题】:T-SQL function that returns TABLE using dynamic SQL使用动态 SQL 返回 TABLE 的 T-SQL 函数
【发布时间】:2018-03-21 01:32:17
【问题描述】:

编辑:一些愿意提供帮助的人不清楚要求的性质,所以我会尽可能清楚地说明:

我们需要实例化一个底层表的视图,并且这个视图必须能够连接到另一个表;困难在于在执行连接的临时查询运行时才知道底层表的身份。 我们想做这样的事情:

  select * from foo
   inner join dynamicallyInstantiatedTable(condition) DT
   on foo.zipcode = DT.zipcode

如果函数使用动态 SQL,则似乎无法创建返回 TABLE 的函数。这是无效的:

   declare @tablename varchar(50);
   -- <snip> code to determine the name of @tablename

   declare @statement varchar(1000);
   set @statement = 'select * from ' + @tablename;
   exec( @statement);

错误:

在 功能。

如果由于某种原因事先不知道表名(例如,表不断被添加,我们必须选择最近的表),是否可以动态进行选择并且在存储过程或函数中返回一个表?

【问题讨论】:

  • SP 是否可以返回表,以便将其视为表,即存储的 proc 名称在另一个 select 语句中充当表名? select * from myproc inner join T....
  • @Tim 啊,我明白你在问什么。不幸的是,不,您不能在存储过程、视图或函数中执行此操作。您可以获得的最接近的是返回结果集的过程,但您不能将其视为表格。
  • 一些非常丑陋的方式SELECT * FROM OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters') 结合动态 SQL 可能有效,但我仍然不会那样做
  • tables are constantly being added and we must select against the most recent one 它表示每个日期的表格,恕我直言,这是糟糕的设计。它是反模式SELECT * FROM sales + @yymm

标签: sql-server function tsql dynamic-sql


【解决方案1】:

我们开始吧。

我不经常使用同义词,但 CREATE SYNONYM 支持动态 SQL。

declare @tablename nvarchar(128);
-- <some code to set @tablename>

declare @sql nvarchar(500);

if object_id(N'dbo.TodaysData', N'SN') is not null
    drop synonym dbo.TodaysData;

set @sql = 
    'create synonym dbo.TodaysData
     for ' + @tablename;

execute(@sql);

select top 5 
    *
from 
    dbo.TodaysData as t
    join
    dbo.SomeOtherTable as s
        on 
           s.FieldName = t.HeresHopingYourSchemaDoesntChange

【讨论】:

    【解决方案2】:

    关于“加入”情况的细节很少,但跳到最终的加入结果可能更容易,而不是孤立地关注输入表。

    在这里,我将输入表“a”连接到查找表“ref”,并输出连接结果。 如果明天你有另一个输入表'b' - 这个过程将把它加入到查找表中。 唯一的要求是连接列是一致的。

      declare 
      @inputTableName nvarchar(128)
      ,@sqlExec nvarchar(max)
    
      set @inputTableName = 'b';
    
      if(not exists (select 1 from INFORMATION_SCHEMA.TABLES where table_schema = 'test' and TABLE_NAME = 'myView'))
      begin
            select @sqlExec = 'create view test.myView as 
                                select I.*,R.[text] from test.[' + @inputTableName + '] I inner join test.ref  R on I.col0 = R.col0'
    end else begin
            select @sqlExec = 'alter view test.myView as 
                                select I.*,R.[text] from test.[' + @inputTableName + '] I inner join test.ref  R on I.col0 = R.col0'
    end
        exec (@sqlExec)
    
    select * from test.myView
    

    【讨论】:

    • 感谢您的建议,西蒙。我必须跑,但稍后会检查并返回。
    【解决方案3】:

    你应该用例子说明你的要求。任何人都不清楚。

    我认为所有事情都可以在单个 proc 中完成,不需要另一个 proc 或 UDF。

    declare @tblname varchar(500)
    select  @tblname=name from sys.objects
    where type_desc ='USER_TABLE'
    order by create_date DESC
    
    declare @Sql varchar(max)=''
    set @Sql='select * into #tmp from '+@tblname+'  '
    
    set @Sql=@Sql+' select *  from #tmp   drop table #tmp'
    exec (@Sql)
    

    【讨论】:

      【解决方案4】:

      函数中的动态 SQL。没有。

      是否可以动态进行选择并返回一个表格,或者 在存储过程中或函数?

      也许我遗漏了一些东西(不会是第一个),但这看起来像存储过程一样简单:

      过程

      create proc dbo.getRowsFrom @tablename varchar(50) as
      exec('select * from ' + @tablename);
      

      使用

      exec dbo.getRowsFrom '<my table>';
      

      这就是你要找的吗?

      【讨论】:

      • 我需要将 加入另一个。
      • 啊-好的。说得通。存储过程也出来了。 lad2025 发布的 OPENQUERY 解决方案可能是要走的路。
      猜你喜欢
      • 2016-05-06
      • 2012-02-07
      • 1970-01-01
      • 1970-01-01
      • 2011-03-01
      • 2021-10-21
      • 2010-11-04
      • 2017-06-27
      • 2014-04-20
      相关资源
      最近更新 更多