web-dev-qa-db-fra.com

La procédure stockée du serveur SQL renvoie une table

J'ai une procédure stockée qui prend deux paramètres. Je peux l'exécuter avec succès dans Server Management Studio. Il me montre les résultats qui sont comme je l’attendais. Cependant, il renvoie également une valeur de retour.

Il a ajouté cette ligne,

 SELECT 'Return Value' = @return_value

Je voudrais que la procédure stockée retourne la table, elle me montre dans les résultats, pas la valeur de retour, car j'appelle cette procédure stockée à partir de MATLAB et tout ce qu'elle renvoie est true ou false.

Dois-je spécifier dans ma procédure stockée ce qu'elle doit renvoyer? Si oui, comment spécifier un tableau de 4 colonnes (varchar (10), float, float, float)?

27
mHelpMe

Une procédure ne peut pas retourner une table en tant que telle. Cependant, vous pouvez sélectionner une table dans une procédure et la diriger vers une table (ou une variable de table) comme ceci:

create procedure p_x
as
begin
declare @t table(col1 varchar(10), col2 float, col3 float, col4 float)
insert @t values('a', 1,1,1)
insert @t values('b', 2,2,2)

select * from @t
end
go

declare @t table(col1 varchar(10), col2 float, col3 float, col4 float)
insert @t
exec p_x

select * from @t
59
t-clausen.dk

Envisagez de créer une fonction pouvant renvoyer une table et être utilisée dans une requête.

https://msdn.Microsoft.com/en-us/library/ms186755.aspx

La principale différence entre une fonction et une procédure est qu'une fonction ne modifie aucune table. Il ne retourne qu'une valeur.

Dans cet exemple, je crée une requête pour me donner le nombre de toutes les colonnes d'une table donnée qui ne sont ni nulles ni vides.

Il y a probablement plusieurs façons de nettoyer cela. Mais cela illustre bien une fonction.

USE Northwind

CREATE FUNCTION usp_listFields(@schema VARCHAR(50), @table VARCHAR(50))
RETURNS @query TABLE (
    FieldName VARCHAR(255)
    )
BEGIN
    INSERT @query
    SELECT
        'SELECT ''' + @table+'~'+RTRIM(COLUMN_NAME)+'~''+CONVERT(VARCHAR, COUNT(*)) '+
    'FROM '+@schema+'.'+@table+' '+
          ' WHERE isnull("'+RTRIM(COLUMN_NAME)+'",'''')<>'''' UNION'
    FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @table and TABLE_SCHEMA = @schema
    RETURN
END

Puis en exécutant la fonction avec 

SELECT * FROM usp_listFields('Employees')

produit un nombre de lignes comme:

SELECT 'Employees~EmployeeID~'+CONVERT(VARCHAR, COUNT(*)) FROM dbo.Employees  WHERE isnull("EmployeeID",'')<>'' UNION
SELECT 'Employees~LastName~'+CONVERT(VARCHAR, COUNT(*)) FROM dbo.Employees  WHERE isnull("LastName",'')<>'' UNION
SELECT 'Employees~FirstName~'+CONVERT(VARCHAR, COUNT(*)) FROM dbo.Employees  WHERE isnull("FirstName",'')<>'' UNION
5
Algonaut

Je le fais fréquemment en utilisant des types de table pour assurer plus de cohérence et simplifier le code. Techniquement, vous ne pouvez pas renvoyer "une table", mais vous pouvez renvoyer un jeu de résultats. En utilisant la syntaxe INSERT INTO .. EXEC ..., vous pouvez clairement appeler un PROC et stocker les résultats dans un type de table. Dans l'exemple suivant, je passe en réalité une table dans un PROC avec un autre paramètre dont j'ai besoin pour ajouter une logique, puis je "retourne une table" et je peux ensuite l'utiliser avec une variable de table.

/****** Check if my table type and/or proc exists and drop them ******/
IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'returnTableTypeData')
DROP PROCEDURE returnTableTypeData
GO
IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = 'myTableType')
DROP TYPE myTableType
GO

/****** Create the type that I'll pass into the proc and return from it ******/
CREATE TYPE [dbo].[myTableType] AS TABLE(
    [someInt] [int] NULL,
    [somenVarChar] [nvarchar](100) NULL
)
GO

CREATE PROC returnTableTypeData
    @someInputInt INT,
    @myInputTable myTableType READONLY --Must be readonly because
AS
BEGIN

    --Return the subset of data consistent with the type
    SELECT
        *
    FROM
        @myInputTable
    WHERE
        someInt < @someInputInt

END
GO


DECLARE @myInputTableOrig myTableType
DECLARE @myUpdatedTable myTableType

INSERT INTO @myInputTableOrig ( someInt,somenVarChar )
VALUES ( 0, N'Value 0' ), ( 1, N'Value 1' ), ( 2, N'Value 2' )

INSERT INTO @myUpdatedTable EXEC returnTableTypeData @someInputInt=1, @myInputTable=@myInputTableOrig

SELECT * FROM @myUpdatedTable


DROP PROCEDURE returnTableTypeData
GO
DROP TYPE myTableType
GO
5
rainabba

Vous pouvez utiliser un paramètre out au lieu de la valeur renvoyée si vous souhaitez un ensemble de résultats et une valeur renvoyée.

CREATE PROCEDURE proc_name 
@param int out
AS
BEGIN
    SET @param = value
SELECT ... FROM [Table] WHERE Condition
END
GO
3
SpaceghostAli

J'ai eu une situation similaire et résolu en utilisant une table temporaire à l'intérieur de la procédure, avec les mêmes champs retournés par la procédure stockée d'origine:

CREATE PROCEDURE mynewstoredprocedure
AS 
BEGIN

INSERT INTO temptable (field1, field2)
EXEC mystoredprocedure @param1, @param2

select field1, field2 from temptable

-- (mystoredprocedure returns field1, field2)

END
2
Cassio Veras

La valeur de statut renvoyée par une procédure stockée ne peut être qu'un type de données INT. Vous ne pouvez pas renvoyer d'autres types de données dans l'instruction RETURN.

De Leçon 2: Conception de procédures stockées :

Chaque procédure stockée peut renvoyer une valeur integer connue sous le nom de valeur du statut d'exécution ou code de retour.

Si vous souhaitez toujours obtenir une table renvoyée du SP, vous devrez soit utiliser le jeu d'enregistrements renvoyé à partir d'un SELECT dans SP, soit l'associer à une variable OUTPUT qui transmet un type de données XML.

HTH,

John

2
John Eisbrener
create procedure PSaleCForms
as
begin
declare 
@b varchar(9),
@c nvarchar(500),
@q nvarchar(max)
declare @T table(FY nvarchar(9),Qtr int,title nvarchar    (max),invoicenumber     nvarchar(max),invoicedate datetime,sp decimal    18,2),grandtotal decimal(18,2))
declare @data cursor
set @data= Cursor
forward_only static
for 
select x.DBTitle,y.CurrentFinancialYear from [Accounts     Manager].dbo.DBManager x inner join [Accounts Manager].dbo.Accounts y on        y.DBID=x.DBID where x.cfy=1
open @data
fetch next from @data
into @c,@b
while @@FETCH_STATUS=0
begin
set @q=N'Select '''+@b+''' [fy], case cast(month(i.invoicedate)/3.1 as int)     when 0 then 4 else cast(month(i.invoicedate)/3.1 as int) end [Qtr],     l.title,i.invoicenumber,i.invoicedate,i.sp,i.grandtotal from     ['+@c+'].dbo.invoicemain i inner join  ['+@c+'].dbo.ledgermain l on     l.ledgerid=i.ledgerid where (sp=0 or stocktype=''x'') and invoicetype=''DS'''

insérer dans @T exec [maître] .dbo.sp_executesql @q extraire ensuite de @data dans @ c, @ b fin fermer @data traiter. @louer. sélectionnez * de @T return end 

0
Rohit