[英]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.