簡體   English   中英

如何使用SQL中存儲過程的值填充結果視圖列?

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM