【问题标题】:TSQL: Using a Table in a Variable in a FunctionTSQL:在函数的变量中使用表
【发布时间】:2013-07-26 20:32:43
【问题描述】:

我正在尝试从需要在变量中的表中进行选择。我正在使用从应用程序动态创建的表。该表将命名为 CMDB_CI_XXX,其中 XXX 将是基于另一个表中的值的整数值。最终目标是从表中获取 CI 名称。

我尝试将组成表名的部分传递给函数并将它们串在一起,然后返回名称值,但我不允许在函数中使用 EXEC 语句。

这就是我要执行以获取名称值的内容:

Select [Name] from 'CMDB_CI_' + C.CI_TYPE_ID + Where CI_ID = c.CI_ID

这是我想在其中使用函数来获取名称值的 SP 中的代码:

SELECT  
  CI_ID,
  C.CI_TYPE_ID,
  CI_CUSTOM_ID,
  STATUS,
  CI_TYPE_NAME,
  --(Select [Name] from CMDB_CI_ + C.CI_TYPE_ID + Where CI_ID = c.CI_ID)   
FROM [footprints].[dbo].[CMDB50_CI_COMMON] c
join [footprints].[dbo].[CMDB50_CI_TYPE] t
on c.CI_TYPE_ID = t.CI_TYPE_ID 
where status <> 'retired'
order by CI_TYPE_NAME 

我不知道该怎么办。请帮忙?

谢谢, 詹妮弗

【问题讨论】:

  • 哇,这听起来很糟糕,为什么要在应用程序中动态创建表 - 如果它们在 3 个字符上不同,您应该有一个名为 CMDB_CI 的表和一个长度为 3 个字符的列来存储代码。您不想在 SQL 中动态创建表。也就是说,我会回答您的问题,您使用的是什么平台,SQL Server、DB2、Oracle 或 mySQL 或 Progress?
  • 您不能在 SQL 查询中对表进行参数化。我同意@Hogan - 看起来你最终得到了一些你希望能够查询的数据实际上嵌入在表名中 - 这是数据和元数据的错误混合。
  • 我使用的是 SQL Server 2008。我问应用程序的支持团队为什么这样设置,并被告知因为表是为属性设置的,然后每种类型可以有不同的属性每个属性的列名可能不同。一个列名可能是“Color”,另一个可能是“SerialNumber”。但我完全同意你的看法。我会以非常不同的方式进行设置。
  • @Jennifer - 属性名称应该在不同的表中。这显然是一个糟糕的设计。 SQL 确实让您“动态”了一个语句,如我的回答所示。它会比非动态 SQL 慢。

标签: sql sql-server function variables dynamic


【解决方案1】:
-- This part would be a SP parameter I expect
DECLARE @tableName varchar(100)
SET @tableName = 'CMDB_CI_508'

-- Main SP code
DECLARE @sqlStm VARCHAR(MAX)

SET @sqlStm = 'SELECT * 
FROM '+ @tableName

EXEC (@sqlStm)

小提琴http://sqlfiddle.com/#!3/436a7/7

【讨论】:

  • 我会做类似Declare @suffix char(3), @tableName varchar(100); set @tableName = 'CMDB_CI_'+@suffix 这样的事情,这将使注入攻击更加困难。
  • @KM - 是的,这会更好,因为它是“更干净的代码”。我只是在这里做一个动态 SQL 的例子。在注入方面,程序员应该只使用参数化查询和 SP -ALWAYS!!
  • 那行不通。问题是我不能在函数中使用 EXEC 语句。据我所知,如果我将表名传递给存储过程,我不能从 select 子句中做到这一点。我需要对从表返回的每一行执行此操作。我真正需要的是这样的:SELECT CI_ID, C.CI_TYPE_ID, CI_CUSTOM_ID, STATUS, CI_TYPE_NAME, UDF_GetCIName (C.CI_TYPE_ID C.CI_ID) FROM [footprints].[dbo].[CMDB50_CI_COMMON] c join [footprints].[ dbo].[CMDB50_CI_TYPE] t on c.CI_TYPE_ID = t.CI_TYPE_ID where status 'retired' order by CI_TYPE_NAME
  • @Jennifer - 好的,两个表名是动态的——函数的动态是什么?函数有什么作用?
【解决方案2】:

首先,是的,我知道这是一个糟糕的设计。我没有设计它。它附带了我公司为我们的呼叫中心购买的问题跟踪软件。所以我完全放弃了我想要的方法,并使用游标将所有名称从各种表中拉到一个临时表中,然后使用所述临时表加入原始查询。

ALTER Proc [dbo].[CI_CurrentItems]

As

Declare @CIType nvarchar(6)
Declare @Qry nvarchar(100)
/*
Create Table Temp_CI 
( T_CI_ID int,
  T_CI_Type_ID int,
  T_Name nvarchar(400)
)
*/

Truncate Table Temp_CI

Declare CI_Cursor Cursor For 
select distinct CI_TYPE_ID  FROM [footprints].[dbo].[CMDB50_CI_COMMON]
where STATUS <> 'Retired'

Open CI_Cursor

Fetch Next from CI_Cursor into @CIType

While @@FETCH_STATUS = 0
BEGIN
Set @Qry = 'Select CI_ID, CI_Type_ID, Name from Footprints.dbo.CMDB50_CI_' + @CIType 
Insert into Temp_CI Exec (@Qry)
Fetch Next from CI_Cursor into @CIType
END

Close CI_Cursor
Deallocate CI_Cursor

SELECT  CI_ID,
    C.CI_TYPE_ID,
    CI_CUSTOM_ID,
    STATUS,
    CI_TYPE_NAME,
    T_Name
FROM [footprints].[dbo].[CMDB50_CI_COMMON] c
JOIN [footprints].[dbo].[CMDB50_CI_TYPE] t
ON c.CI_TYPE_ID = t.CI_TYPE_ID 
JOIN Temp_CI tc
ON c.CI_ID = tc.T_CI_ID
AND t.CI_TYPE_ID = tc.T_CI_TYPE_ID
WHERE STATUS <> 'retired'
ORDER BY CI_TYPE_NAME 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多