SQL Server - SELECT จากกระบวนงานที่เก็บไว้


334

ฉันมีขั้นตอนการจัดเก็บที่ส่งคืนแถว:

CREATE PROCEDURE MyProc
AS
BEGIN
    SELECT * FROM MyTable
END

ขั้นตอนจริงของฉันนั้นซับซ้อนกว่าเล็กน้อยซึ่งเป็นเหตุผลว่าทำไมจึงจำเป็นต้องมีสไปรค

เป็นไปได้หรือไม่ที่จะเลือกเอาต์พุตโดยเรียกโพรซีเดอร์นี้?

สิ่งที่ต้องการ:

SELECT * FROM (EXEC MyProc) AS TEMP

ฉันต้องใช้SELECT TOP X, ROW_NUMBERและอีกWHEREข้อที่หน้าข้อมูลของฉันและฉันไม่ต้องการที่จะผ่านค่าเหล่านี้เป็นพารามิเตอร์


ฉันไม่แน่ใจว่าคุณตั้งใจจะทำอะไรที่นี่เพราะเมื่อคุณดำเนินการตามขั้นตอนคุณจะได้แถวกลับมา มันเป็นที่คุณต้องการที่จะดำเนินการตามขั้นตอนภายในคำสั่ง SELECT เพื่อให้คุณสามารถผูกมันเป็นวัตถุที่สามารถเพจได้หรือไม่?
30932 Raj ขึ้น

1
มีเหตุผลบางอย่างที่ทำให้คุณไม่ต้องการส่งผ่านค่าเป็นพารามิเตอร์หรือไม่ ในการทำสิ่งที่คุณกำลังแนะนำนั้นค่อนข้างไร้ประสิทธิภาพ - คุณจะต้องเลือกข้อมูลมากกว่าที่คุณต้องการจากนั้นไม่ได้ใช้มันทั้งหมด
Mark Bell

2
ดูที่นี่: sommarskog.se/share_data.html
pylover

คำตอบ:


149

คุณสามารถใช้ฟังก์ชั่นที่ผู้ใช้กำหนดเองหรือมุมมองแทนขั้นตอน

โพรซีเดอร์สามารถส่งคืนชุดผลลัพธ์ได้หลายชุดโดยแต่ละชุดมีสคีมาของตนเอง มันไม่เหมาะสำหรับใช้ในSELECTคำสั่ง


8
นอกจากนี้หากหลังจากแปลงเป็น UDF คุณจะพบว่าคุณต้องการซีแมนทิกส์ของโพรซีเดอร์ที่เก็บไว้คุณสามารถล้อม UDF ด้วยโพรซีเดอร์ได้เสมอ
Joel Coehoorn

จะทำอย่างไรถ้าเราต้องการส่งพารามิเตอร์ไปยังโพรซีเดอร์ที่เก็บไว้ขนาดใหญ่และรวมเข้ากับโพรซีเดอร์ที่เก็บขนาดใหญ่หนึ่งเดียว สามารถดูรับพารามิเตอร์ได้เช่นเดียวกับขั้นตอนการจัดเก็บ
mrN

3
@mrN Views ไม่รับพารามิเตอร์ แต่ทำ UDF
Mehrdad Afshari

3
สวัสดีฉันต้องทำสิ่งนี้โดยไม่แปลง sp เป็นมุมมองหรือฟังก์ชั่นเป็นไปได้หรือไม่
Luis Becerril

2
ในขณะที่คำตอบของคุณคือข้อความจริงมันไม่ได้ตอบคำถาม .... "เลือกจากกระบวนงานที่เก็บไว้" ซึ่งแน่นอนว่ามันไม่เหมาะ แต่เป็นสิ่งที่เป็น ... @ คำตอบของ Aamir คือคำตอบที่ถูกต้อง ไม่ว่าจะเป็นคำถามหรือต้องเปลี่ยน ... ซึ่งดูเหมือนจะไร้สาระสำหรับฉัน
Urasquirrel

202

คุณสามารถ

  1. สร้างตัวแปรตารางเพื่อเก็บชุดผลลัพธ์จาก proc ที่เก็บไว้แล้ว
  2. แทรกผลลัพธ์ของ proc ที่เก็บไว้ลงในตัวแปรตารางแล้ว
  3. ใช้ตัวแปรตารางตรงตามที่คุณต้องการในตารางอื่น ๆ ...

... sql ....

Declare @T Table ([column definitions here])
Insert @T Exec storedProcname params 
Select * from @T Where ...

34
ปัญหาที่เกิดขึ้นกับINSERT #TหรือINSERT @Tว่าINSERT EXECคำสั่งไม่สามารถซ้อนกัน หากขั้นตอนการจัดเก็บมีอยู่แล้วในขั้นตอนINSERT EXECนี้จะไม่ทำงาน
MOHCTP

2
นี่อาจเป็นโซลูชันแบบพกพาที่ใกล้เคียงที่สุดกับ SQL พื้นฐาน นอกจากนี้ยังช่วยในการรักษาคำจำกัดความประเภทคอลัมน์ที่แข็งแกร่ง ควรมี upvotes มากกว่าที่กล่าวไว้ด้านบน

ตัวแปรตารางดูเหมือนมีประโยชน์มากขึ้นที่นี่กว่าตารางชั่วคราวในแง่ของ SP คอมไพล์ ดังนั้นฉันเห็นด้วยคำตอบนี้ควรมี upvotes มากขึ้น
resnyanskiy

76

คุณต้องการฟังก์ชั่น Table-Valuedหรือแทรก EXEC ของคุณลงในตารางชั่วคราว:

INSERT INTO #tab EXEC MyProc

32
ปัญหาที่เกิดขึ้นกับINSERT #TหรือINSERT @Tว่าINSERT EXECคำสั่งไม่สามารถซ้อนกัน หากขั้นตอนการจัดเก็บมีอยู่แล้วในขั้นตอนINSERT EXECนี้จะไม่ทำงาน
MOHCTP

46

คุณต้องอ่านเกี่ยวกับOPENROWSETและOPENQUERY

SELECT  * 
INTO    #tmp FROM    
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters')

4
วิธีรับ YourSERVERNAME แบบไดนามิก คุณไม่สามารถคาดหวังได้ว่าจะต้องรู้อยู่เสมอ จะไม่หยุดกันทุกวันอังคารหรือไม่ ดังนั้นถ้าฉันมีเซิร์ฟเวอร์ 100 เครื่องที่มีชื่อแตกต่างกัน ...
27490

ยังจะเกิดอะไรขึ้นถ้าฐานข้อมูลของฉันไม่ได้กำหนดค่าให้ใช้สิ่งนี้
Urasquirrel

4
ลอง @@ ชื่อเซิร์ฟเวอร์เพื่อรับมันแบบไดนามิก
Siddhartha Gandhi

44

คุณต้องประกาศประเภทตารางที่มีจำนวนคอลัมน์เท่ากันกับที่ร้านค้าของคุณส่งคืน ชนิดข้อมูลของคอลัมน์ในประเภทตารางและคอลัมน์ที่ส่งคืนโดยโพรซีเดอร์ควรเหมือนกัน

declare @MyTableType as table
(
FIRSTCOLUMN int
,.....
)  

จากนั้นคุณต้องแทรกผลลัพธ์ของกระบวนงานที่เก็บไว้ในประเภทตารางที่คุณเพิ่งกำหนด

Insert into @MyTableType 
EXEC [dbo].[MyStoredProcedure]

ในท้ายที่สุดเพียงแค่เลือกจากประเภทตารางของคุณ

Select * from @MyTableType

นั่นเป็นทางออกที่ดีที่สุดสำหรับฉันเพราะคุณไม่จำเป็นต้องระบุชื่อเซิร์ฟเวอร์สตริงการเชื่อมต่อหรือต้องกำหนดค่าเซิร์ฟเวอร์ที่ถูกเชื่อมโยงใด ๆ เพื่อให้มันทำงาน - ซึ่งเป็นสิ่งที่ฉันไม่ต้องการทำเพื่อให้ได้ ข้อมูลบางอย่างกลับมา ขอบคุณ! คำตอบที่น่ากลัว!
Matt

คำตอบที่ดีღ❤ ೋ ღ❤ღ ೋ❤ ღ
Nahid

เมื่อโพรซีเดอร์ที่เก็บไว้มี dificult มากเกินไป - เมธอดนี้ไม่ทำงานตัวอย่างเช่นเมื่อโพรซีเดอร์ที่เก็บใช้สองเทมเพลตตาราง
nick_n_a

34

ไม่จำเป็นต้องใช้ตารางชั่วคราว

นี่คือทางออกของฉัน

SELECT  *  FROM    
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters')
WHERE somefield = anyvalue

2
สิ่งนี้ต้องการให้คุณเพิ่มเซิร์ฟเวอร์ของคุณเป็นเซิร์ฟเวอร์ที่เชื่อมโยงเข้ากับตัวมันเอง แต่มันก็ใช้งานได้อย่างยอดเยี่ยม! ขอบคุณ!
vaheeds

คำเตือนที่ดีบางประการเกี่ยวกับเรื่องนี้: stackoverflow.com/questions/2374741/…
Keith Adler

1
อืม ... ฉันได้รับข้อผิดพลาด "ข้อผิดพลาด 7411: เซิร์ฟเวอร์ 'YourServerName' ไม่ได้รับการกำหนดค่าสำหรับ DATA ACCESS" ฉันต้องเปลี่ยนอะไร
Matt

คุณเพิ่มเซิร์ฟเวอร์ของคุณเป็นเซิร์ฟเวอร์ที่เชื่อมโยงหรือไม่ YourServerName เป็นชื่อเซิร์ฟเวอร์ของคุณ คุณต้องเปลี่ยน YourServerName ด้วยชื่อเซิร์ฟเวอร์จริงของคุณ
DavideDM

sp_serveroption 'MYSERVER', 'DATA ACCESS', TRUE;
@Matt

23

คุณสามารถคัดลอกผลลัพธ์จาก sp ไปยังตารางชั่วคราว

CREATE TABLE #GetVersionValues
(
    [Index] int,
    [Name]  sysname,
    Internal_value  int,
    Character_Value sysname
)
INSERT #GetVersionValues EXEC master.dbo.xp_msver 'WindowsVersion'
SELECT * FROM #GetVersionValues
drop TABLE #GetVersionValues

7

ใช้ OPENQUERY และ befor Execute set 'SET FMTONLY OFF; SET NOCOUNT ON; '

ลองรหัสตัวอย่างนี้:

SELECT top(1)*
FROM
OPENQUERY( [Server], 'SET FMTONLY OFF; SET NOCOUNT ON; EXECUTE  [database].[dbo].[storedprocedure]  value,value ')

6

ลองแปลงกระบวนงานของคุณเป็นฟังก์ชันอินไลน์ซึ่งส่งกลับตารางดังนี้

CREATE FUNCTION MyProc()
RETURNS TABLE AS
RETURN (SELECT * FROM MyTable)

จากนั้นคุณสามารถเรียกมันว่า

SELECT * FROM MyProc()

คุณยังมีตัวเลือกในการส่งพารามิเตอร์ไปยังฟังก์ชันดังนี้:

CREATE FUNCTION FuncName (@para1 para1_type, @para2 para2_type , ... ) 

และเรียกมันว่า

SELECT * FROM FuncName ( @para1 , @para2 )

6

หาก 'DATA ACCESS' เป็นเท็จ

EXEC sp_serveroption 'SQLSERVERNAME', 'DATA ACCESS', TRUE

หลังจาก,

SELECT  *  FROM OPENQUERY(SQLSERVERNAME, 'EXEC DBNAME..MyProc @parameters')

มันได้ผล.


5

คุณสามารถโกงหน่อยได้ด้วย OPENROWSET:

SELECT ...fieldlist...
FROM OPENROWSET('SQLNCLI', 'connection string', 'name of sp')
WHERE ...

สิ่งนี้จะยังคงรัน SP ทั้งหมดได้ทุกครั้ง


4

เพื่อความเรียบง่ายและเพื่อให้สามารถเรียกใช้ซ้ำได้ฉันได้ใช้ระบบ StoredProcedure "sp_readerrorlog" เพื่อรับข้อมูล:

-----USING Table Variable
DECLARE @tblVar TABLE (
   LogDate DATETIME,
   ProcessInfo NVARCHAR(MAX),
   [Text] NVARCHAR(MAX)
)
INSERT INTO @tblVar Exec sp_readerrorlog
SELECT LogDate as DateOccured, ProcessInfo as pInfo, [Text] as Message FROM @tblVar



-----(OR): Using Temp Table
IF OBJECT_ID('tempdb..#temp') IS NOT NULL  DROP TABLE #temp;
CREATE TABLE #temp (
   LogDate DATETIME,
   ProcessInfo NVARCHAR(55),
   Text NVARCHAR(MAX)
)
INSERT INTO #temp EXEC sp_readerrorlog
SELECT * FROM #temp

1

มันเสียงเหมือนคุณก็อาจจะต้องใช้มุมมอง มุมมองช่วยให้แบบสอบถามที่จะแสดงเป็นตารางดังนั้นมันสามารถสอบถามมุมมอง


1

หากเซิร์ฟเวอร์ของคุณชื่อ SERVERX นี่เป็นวิธีที่ฉันทำ ...

EXEC sp_serveroption 'SERVERX', 'DATA ACCESS', TRUE;
DECLARE @CMD VARCHAR(1000);
DECLARE @StudentID CHAR(10);
SET @StudentID = 'STUDENT01';
SET @CMD = 'SELECT * FROM OPENQUERY([SERVERX], ''SET FMTONLY OFF; SET NOCOUNT ON; EXECUTE MYDATABASE.dbo.MYSTOREDPROC ' + @StudentID + ''') WHERE SOMEFIELD = SOMEVALUE';
EXEC (@CMD);

เพื่อตรวจสอบสิ่งนี้ใช้งานได้ฉันใส่เครื่องหมายคอมEXEC()เม้นต์บรรทัดคำสั่งและแทนที่ด้วยSELECT @CMDเพื่อตรวจสอบคำสั่งก่อนที่จะพยายามรัน! นั่นคือเพื่อให้แน่ใจว่าจำนวนคำพูดเดียวที่ถูกต้องทั้งหมดอยู่ในตำแหน่งที่ถูกต้อง :-)

ฉันหวังว่าจะช่วยใครบางคน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.