[英]How do I Populate a Result View Column with Value from Stored Proc in SQL?
编辑:是一个存储过程,而不是一个功能 ,对不起!
我有一张桌子:
TABLE: dbo.Numbers
Number_ID | Number
1 | 0
2 | 1
3 | 2
4 | 3
5 | 4
6 | 5
7 | 6
8 | 7
我想要以下输出( 作为视图 ):
Number_ID | ModifiedNumber
1 | lol the num is 0
2 | lol the num is 1
3 | lol the num is 2
4 | lol the num is 3
5 | lol the num is 4
6 | lol the num is 5
7 | lol the num is 6
8 | lol the num is 7
我有一个存储过程来执行此操作:
CREATE PROCEDURE dbo.UselessStoredProc @inputNum int
AS
SELECT 'lol my number is: ' + CONVERT(varchar(max), @inputNum)
GO
--TEST
EXEC dbo.UselessStoredProc @inputNum=2;
我的最终目标是通过存储过程填充ModifiedNumber
col,例如:
SELECT Number_ID, EXEC UselessStoredProc @inputNum = Number_ID as ModifiedNumber
FROM [TestDb].[dbo].[Numbers]
显然这不起作用。 我该如何做到这一点。
PS请不要告诉我“只是这样做:
SELECT Number_ID, 'lol my number is: ' + CONVERT(varchar(max), Number_ID) as ModifiedNumber
FROM [TestDb].[dbo].[Numbers]
“
我很清楚我能做到这一点 - 这显然是一个例子,真正的代码要复杂得多,需要一个存储过程 。 注意,我故意从样本存储过程中返回一个字符串 - 我需要复杂的值,而不仅仅是int
。
编辑:
SQL Server 2012
功能不是一种选择。 我为这种困惑道歉。 我的“函数”需要调用内置的存储过程,函数不能这样做。
编辑2:我需要SP而不是函数的原因是因为我需要动态查找某些表的主键,所以我需要使用动态SQL。 我认为这是太多的信息,但看起来有必要:
DECLARE @sql nvarchar(max) = 'SELECT @Data_Table_Key = COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE OBJECTPROPERTY(OBJECT_ID(CONSTRAINT_SCHEMA + ''.'' + QUOTENAME(CONSTRAINT_NAME)), ''IsPrimaryKey'') = 1 AND TABLE_NAME = ''' + @Data_Table_Name + ''''
EXECUTE sp_executesql @sql, N'@Data_Table_Key varchar(200) OUTPUT', @Data_Table_Key OUTPUT
编辑:最后,我试图做一些无法用openrowset做的事情 ,这是一个肮脏,肮脏的黑客。 我最后写了一个存储过程,每5分钟写一个表,第三方软件使用该表。 我感谢所有的帮助。 我接受了最能帮助我的答案,但是循环答案也很有帮助,并得到了我需要的东西,尽管表现令人无法接受。
基于
编辑2:我需要SP而不是函数的原因是因为我需要动态查找某些表的主键,所以我需要使用动态SQL。 我认为这是太多的信息,但看起来有必要:
DECLARE @sql nvarchar(max) = 'SELECT @Data_Table_Key = COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE OBJECTPROPERTY(OBJECT_ID(CONSTRAINT_SCHEMA + ''.'' + QUOTENAME(CONSTRAINT_NAME)), ''IsPrimaryKey'') = 1 AND TABLE_NAME = ''' + @Data_Table_Name + ''''
EXECUTE sp_executesql @sql, N'@Data_Table_Key varchar(200) OUTPUT', @Data_Table_Key OUTPUT
我糊涂了。 为什么要在动态SQL中首先执行此操作。
你也可以这样做:
SELECT @Data_Table_Key = COLUMN_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE OBJECTPROPERTY(OBJECT_ID(CONSTRAINT_SCHEMA + '.' + QUOTENAME(CONSTRAINT_NAME)), 'IsPrimaryKey') = 1
AND TABLE_NAME = @Data_Table_Name
并在@Data_Table_Key
变量中得到相同的结果。
也就是说,只要您尝试从主键中包含多个字段的表中获取PK列,您的方法就会给您“不完整”的结果。 不知道你会得到哪一个,但它只是其中之一(通常是最后一个,但你不能指望它!)。
一些示例代码:
CREATE TABLE t_test_multiple_pk_fields ( key1 int NOT NULL,
key2 int NOT NULL,
constraint pk_test PRIMARY KEY (key1, key2),
value1 int,
value2 int)
DECLARE @Data_Table_Name sysname,
@Data_Table_Key sysname
SELECT @Data_Table_Name = 't_test_multiple_pk_fields'
SELECT Data_Table_Key = COLUMN_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE OBJECTPROPERTY(OBJECT_ID(CONSTRAINT_SCHEMA + '.' + QUOTENAME(CONSTRAINT_NAME)), 'IsPrimaryKey') = 1
AND TABLE_NAME = @Data_Table_Name
SELECT @Data_Table_Key = COLUMN_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE OBJECTPROPERTY(OBJECT_ID(CONSTRAINT_SCHEMA + '.' + QUOTENAME(CONSTRAINT_NAME)), 'IsPrimaryKey') = 1
AND TABLE_NAME = @Data_Table_Name
SELECT @Data_Table_Key
由于SQL Server是为批处理而设计的,因此应尽可能避免处理数据RBAR ,但我正在假设您在此问题上没有选择权。 考虑到这一假设,这应该实现您所追求的目标:
-- Generate some dummy data
Declare @Numbers Table
(
Number_ID int primary key,
Number varchar(100)
)
;with cte as
(
select 1 [Value]
union all
select value+1 from cte where (value+1) < 9
)
insert into @Numbers(Number_ID, number)
select value, convert(varchar(100), value-1) from cte
-- Process the records, one at a time
declare @id int=0
declare @result table (value varchar(100))
while (1=1)
begin
-- Get the ID of the next record for processing
select @id=min(number_id) from @numbers where number_id>@id
if (@id is null)
break
-- Call the useless stored procedure and dump the results into a temp table (table layout must match that of the resultset from the SP)
insert into @result(value)
exec UselessStoredProc @id
-- Copy the value from the temp table to the appropriate record in your numbers table
update n set Number=r.value
from @numbers n
cross join @result r
where n.Number_ID=@id
-- Clear out the temp table, ready for your next value
delete from @result
end
-- Show the results
select * from @Numbers
我在这里使用WHILE循环遍历你的数字表,因为它比CURSOR更有效(或者我应该说效率更低)。
再说一次,如果有任何方法可以避免RBAR模式,那么我会去寻找它。
你的问题毫无意义,只是为了显示一个选项,这是一种使用表类型参数的方法。
创建一个名为udtNumbers
的表类型。 这将用于将数字作为输入参数传递给过程。 最重要的是避免RBAR
create type udtNumbers(Number_ID int, Number int)
更改过程以接受表类型作为输入参数。
Alter PROCEDURE dbo.UselessStoredProc @inputNum udtNumbers READONLY
AS
SELECT Number_ID, 'lol my number is: ' + CONVERT(varchar(max), Number)
from @inputNum
GO
现在打电话给程序
Declare @inputNum udtNumbers
insert into @inputNum(Number_ID, Number)
select Number_ID, Number
from dbo.Numbers
exec dbo.UselessStoredProc @inputNum
希望这可以帮助您以某种方式解决您的现实世界问题
绝对可以在视图中使用函数。 你没有说明应该如何修改数字,除了显示它减少1.这就是说该函数应该能够完成你想要的任何逻辑。 简单地说,这将是(使用AdventureWorks表)...
DROP FUNCTION IF EXISTS dbo.UselessFunction1
go
CREATE FUNCTION dbo.UselessFunction1(@inputnum int)
RETURNS varchar(30)
AS
BEGIN
DECLARE @outputString varchar(30)
SELECT @outputString = 'lol my number is ' + CAST(@inputnum-1 AS varchar(10))
RETURN @outputString
END
GO
DROP VIEW IF EXISTS dbo.UselessView1
go
CREATE VIEW dbo.UselessView1 AS
SELECT Name,dbo.UselessFunction1(pc.ProductCategoryID) AS Number_ID
FROM Production.ProductCategory AS pc
GO
SELECT * FROM dbo.UselessView1 AS uv;
从性能角度来看,标量函数当然不是理想的,所以如果你可以通过单个查询来执行UselessStoredProc正在执行的任何逻辑,那么内联表值函数会更好,例如......
DROP FUNCTION IF EXISTS dbo.UselessFunction2
go
CREATE FUNCTION dbo.UselessFunction2(@inputnum int)
RETURNS TABLE
AS
RETURN (
SELECT 'lol my number is ' + CAST(@inputnum-1 AS varchar(10)) AS Number_ID
)
GO
DROP VIEW IF EXISTS dbo.UselessView2
go
CREATE VIEW dbo.UselessView2 AS
SELECT Name,x.Number_ID
FROM Production.ProductCategory AS pc
CROSS APPLY (SELECT Number_ID FROM dbo.UselessFunction2(pc.ProductCategoryID)) x
GO
SELECT * FROM dbo.UselessView1 AS uv;
另一种方法是预先制作一个“巨大”的视图,它结合了应用程序可能希望看到的所有可能的表。
例如,某些东西
CREATE TABLE t_tableA (keyA int NOT NULL PRIMARY KEY, valueA1 varchar(10), valueA2 datetime)
CREATE TABLE t_tableB (keyB int NOT NULL PRIMARY KEY, valueB1 int, valueB2 varchar(500), valueB3 int)
GO
CREATE VIEW v_all_tables
AS
SELECT table_name = 't_tableA', table_key = keyA, table_value = Convert(nvarchar(max), valueA1) + ' - ' + Convert(nvarchar(max), valueA2)
FROM t_tableA
UNION ALL
SELECT table_name = 't_tableB', table_key = keyB, table_value = '[' + Convert(nvarchar(max), valueB1) + '] ' + Convert(nvarchar(max), valueB2) + ' = ' + Convert(nvarchar(max), valueB3)
FROM t_tableB
GO
SELECT * FROM v_all_tables WHERE table_name = 't_tableA'
这是一个视图,它将是“实时”,您可以轻松过滤掉您需要的表格。 这可能适用于数百个表。 但是,每当您向数据库添加新表时,您都需要更新视图以包含它! 您可能希望编写一个存储过程来删除/创建视图并在每晚或每当添加新表时运行它,而不是编写一个获取数据的存储过程。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.