简体   繁体   English

传递表并将表返回到存储过程或函数?

[英]Pass a table and return a table to a stored procedure or function?

I would like to pass a table to either a UDF or stored procedure and then have it process the data and return the sensitivity, specificity and 95% Upper/Lower Confidence Intervals (for each) from the table I pass to it. 我想将一个表传递给UDF或存储过程,然后让它处理数据并从我传递给它的表中返回灵敏度,特异性和95%的上/下置信区间(每个)。

Basically, from a table I need to calculate and return six values. 基本上,我需要从一个表中计算并返回六个值。

I have to do this a bunch of times so automation would be awesome but I have not created a UDF or SP. 我必须这样做很多次,所以自动化会很棒,但是我还没有创建UDF或SP。 I have read up on them (stackoverflow and elsewhere but am stuck on how to proceed. 我已经阅读了它们(stackoverflow和其他地方,但仍对如何进行操作有所了解。

I created the SQL part to calculate the parameters of interest but I am really befuddled on how to pass a table to it and get a table back out. 我创建了SQL部分来计算感兴趣的参数,但是我对如何将表传递给表以及将表取回感到迷惑不解。

DECLARE @R_MODS TABLE(
  SUBJECTID varchar(max),
  ResultCall varchar(max)
)

INSERT INTO @R_MODS VALUES ('11-0001','TP');
INSERT INTO @R_MODS VALUES ('11-0002','TP');
INSERT INTO @R_MODS VALUES ('11-0003','TP');
INSERT INTO @R_MODS VALUES ('11-0004','TP');
INSERT INTO @R_MODS VALUES ('11-0005','TP');
INSERT INTO @R_MODS VALUES ('11-0006','I');
INSERT INTO @R_MODS VALUES ('11-0007','TP');
INSERT INTO @R_MODS VALUES ('11-0008','TP');
INSERT INTO @R_MODS VALUES ('11-0009','I');
INSERT INTO @R_MODS VALUES ('11-0010','TP');
INSERT INTO @R_MODS VALUES ('11-0011','TP');
INSERT INTO @R_MODS VALUES ('11-0012','TN');
INSERT INTO @R_MODS VALUES ('11-0013','TP');
INSERT INTO @R_MODS VALUES ('11-0014','I');
INSERT INTO @R_MODS VALUES ('11-0015','TP');
INSERT INTO @R_MODS VALUES ('11-0016','TP');
INSERT INTO @R_MODS VALUES ('11-0017','TN');
INSERT INTO @R_MODS VALUES ('11-0018','TP');
INSERT INTO @R_MODS VALUES ('11-0019','FP');
INSERT INTO @R_MODS VALUES ('11-0020','FP');

DECLARE @TP float, @TN float, @FP float, @FN float, @SEN float, @SPE float, @M1 float, 
        @M2 float, @Sen95 float, @SpeL float , @SpeU float, @SenU float, @SenL float

SET @TP = (SELECT COUNT(SUBJECTID) FROM @R_MODS WHERE ResultCall='TP')
SET @TN = (SELECT COUNT(SUBJECTID) FROM @R_MODS WHERE ResultCall='TN')
SET @FP = (SELECT COUNT(SUBJECTID) FROM @R_MODS WHERE ResultCall='FP')
SET @FN = (SELECT COUNT(SUBJECTID) FROM @R_MODS WHERE ResultCall='FN')

SET @SEN = @TP/(@TP + @FN)
SET @M1 = @TP + @FN 

SET @SPE = @TN/(@TN + @FP)
SET @M2 =  @FP + @TN 

SET @SenL = ( 2*@M1*@SEN + POWER(1.96,2) - 1 - 1.96 * SQRT(POWER(1.96,2) 
    - 2 -(1/@M1)+ 4*@SEN *(@M1*(1-@SEN) + 1)))/(2*(@M1+POWER(1.96,2)))
SET @SenU = ( 2*@M1*@SEN + POWER(1.96,2) + 1 + 1.96 * SQRT(POWER(1.96,2) 
    + 2 -(1/@M1)+ 4*@SEN *(@M1*(1-@SEN) - 1)))/(2*(@M1+POWER(1.96,2)))

SET @SpeL = ( 2*@M2*@SPE + POWER(1.96,2) - 1 - 1.96 * SQRT(POWER(1.96,2) 
    - 2 -(1/@M2)+ 4*@SPE *(@M2*(1-@SPE) + 1)))/(2*(@M2+POWER(1.96,2)))
SET @SpeU = ( 2*@M2*@SPE + POWER(1.96,2) + 1 + 1.96 * SQRT(POWER(1.96,2) 
    + 2 -(1/@M2)+ 4*@SPE *(@M2*(1-@SPE) - 1)))/(2*(@M2+POWER(1.96,2)))

SELECT @SEN, @SenL, @SenU, 1-@SPE, 1-@SPEL, 1-@SpeU     

Since your code just does calculations on data (ie no side-effects or updates of tables) and isn't coupled to tables, what you can do is to can create a table valued function to do these calculations - the function can take in the table of inputs ( R_MODS )as a table type and also return a table of outputs ( Sen etc). 由于您的代码仅对数据进行计算(即没有副作用或表更新),并且不与表耦合,因此您可以创建一个表值函数来进行这些计算-该函数可以将输入表( R_MODS )作为表类型 ,还返回输出表( Sen等)。

Here's a SqlFiddle example . 这是SqlFiddle示例

In detail: 详细:

You'll need to create a table type for the inputs, eg 您需要为输入创建表类型,例如

CREATE TYPE R_MODS_TYPE AS TABLE(
  SUBJECTID varchar(max),
  ResultCall varchar(max)
);

And define the function as such: 并这样定义函数:

CREATE FUNCTION dbo.DoCalcs(@TheRMods R_MODS_TYPE READONLY)
RETURNS @Result TABLE
(
    [SEN] DECIMAL(10,4), 
    [SenL] DECIMAL(10,4), 
    [SenU] DECIMAL(10,4),  
    [1-SPE] DECIMAL(10,4), 
    [1-SPEL] DECIMAL(10,4), 
    [1-SpeU] DECIMAL(10,4)
)
AS
BEGIN
    DECLARE @TP float, @TN float, @FP float, @FN float, @SEN float, @SPE float, 
            @M1 float, @M2 float, @Sen95 float, @SpeL float , @SpeU float, 
            @SenU float, @SenL float;

    SET @TP = (SELECT COUNT(SUBJECTID) FROM @TheRMods WHERE ResultCall='TP')
    SET @TN = (SELECT COUNT(SUBJECTID) FROM @TheRMods WHERE ResultCall='TN')
    SET @FP = (SELECT COUNT(SUBJECTID) FROM @TheRMods WHERE ResultCall='FP')
    SET @FN = (SELECT COUNT(SUBJECTID) FROM @TheRMods WHERE ResultCall='FN')

    SET @SEN = @TP/(@TP + @FN)
    SET @M1 = @TP + @FN 

    SET @SPE = @TN/(@TN + @FP)
    SET @M2 =  @FP + @TN 

    SET @SenL = ( 2*@M1*@SEN + POWER(1.96,2) - 1 - 1.96 * SQRT(POWER(1.96,2) 
          - 2 -(1/@M1)+ 4*@SEN *(@M1*(1-@SEN) + 1)))/(2*(@M1+POWER(1.96,2)))
    SET @SenU = ( 2*@M1*@SEN + POWER(1.96,2) + 1 + 1.96 * SQRT(POWER(1.96,2) 
          + 2 -(1/@M1)+ 4*@SEN *(@M1*(1-@SEN) - 1)))/(2*(@M1+POWER(1.96,2)))

    SET @SpeL = ( 2*@M2*@SPE + POWER(1.96,2) - 1 - 1.96 * SQRT(POWER(1.96,2) 
      - 2 -(1/@M2)+ 4*@SPE *(@M2*(1-@SPE) + 1)))/(2*(@M2+POWER(1.96,2)))
    SET @SpeU = ( 2*@M2*@SPE + POWER(1.96,2) + 1 + 1.96 * SQRT(POWER(1.96,2) 
      + 2 -(1/@M2)+ 4*@SPE *(@M2*(1-@SPE) - 1)))/(2*(@M2+POWER(1.96,2)))

    INSERT INTO @Result ([SEN], [SenL], [SenU], [1-SPE], [1-SPEL], [1-SpeU])
        SELECT @SEN, @SenL, @SenU, 1-@SPE, 1-@SPEL, 1-@SpeU;
    RETURN;
END

You then invoke the table function by declaring an instance of the table type, populating it, and passing it to your function: 然后,您通过声明表类型的实例,填充表实例并将其传递给函数来调用表函数:

DECLARE @TestData R_MODS_TYPE;

INSERT INTO @TestData VALUES ('11-0001','TP'),
('11-0002','TP'),
('11-0003','TP'),
('11-0004','TP'),
... etc.

SELECT * FROM dbo.DoCalcs(@TestData);

Result: 结果:

SEN       SenL     SenU    1-SPE   1-SPEL  1-SpeU
--------- -------- ------- ------- ------- -------
1.0000    0.7166   0.9929  0.5000  0.9081  0.0919

Here is another approach using a Stored Procedure 这是使用Stored Procedure另一种方法

You need a user-defined table data type for your input parameter. 您需要输入参数的用户定义表数据类型。

CREATE TYPE R_MODS_TBL AS TABLE(
    SUBJECTID VARCHAR(MAX),
    ResultCall VARCHAR(MAX)
)

And the stored procedure: 和存储过程:

Notice the change on the assignment of variables @TP , @TN , @FP , and @FN to use a single SELECT statement instead of four separate ones. 注意变量@TP@TN@FP@FN的分配更改,以使用单个SELECT语句而不是四个单独的SELECT语句。

CREATE PROCEDURE  dbo.YourStoredProcedure(
    @R_MODS R_MODS_TBL READONLY
)
AS

DECLARE 
    @TP FLOAT, @TN FLOAT, @FP FLOAT, @FN FLOAT,
    @SEN FLOAT, @SPE FLOAT, @M1 FLOAT, @M2 FLOAT, @Sen95 FLOAT,
    @SpeL FLOAT, @SpeU FLOAT, @SenU FLOAT, @SenL FLOAT

SELECT
    @TP = COUNT(CASE WHEN ResultCall='TP' THEN SUBJECTID END),
    @TN = COUNT(CASE WHEN ResultCall='TN' THEN SUBJECTID END),
    @FP = COUNT(CASE WHEN ResultCall='FP' THEN SUBJECTID END),
    @FN = COUNT(CASE WHEN ResultCall='FN' THEN SUBJECTID END)
FROM @R_MODS

SET @SEN = @TP/(@TP + @FN)
SET @M1 = @TP + @FN 

SET @SPE = @TN/(@TN + @FP)
SET @M2 =  @FP + @TN 

SET @SenL = (2*@M1*@SEN + POWER(1.96,2) - 1 - 1.96 * SQRT(POWER(1.96,2) - 2 -(1/@M1)+ 4*@SEN *(@M1*(1-@SEN) + 1)))/(2*(@M1+POWER(1.96,2)))
SET @SenU = (2*@M1*@SEN + POWER(1.96,2) + 1 + 1.96 * SQRT(POWER(1.96,2) + 2 -(1/@M1)+ 4*@SEN *(@M1*(1-@SEN) - 1)))/(2*(@M1+POWER(1.96,2)))

SET @SpeL = (2*@M2*@SPE + POWER(1.96,2) - 1 - 1.96 * SQRT(POWER(1.96,2) - 2 -(1/@M2)+ 4*@SPE *(@M2*(1-@SPE) + 1)))/(2*(@M2+POWER(1.96,2)))
SET @SpeU = (2*@M2*@SPE + POWER(1.96,2) + 1 + 1.96 * SQRT(POWER(1.96,2) + 2 -(1/@M2)+ 4*@SPE *(@M2*(1-@SPE) - 1)))/(2*(@M2+POWER(1.96,2)))

SELECT @SEN, @SenL, @SenU, 1-@SPE, 1-@SPEL, 1-@SpeU 

To execute the stored procedure, you want to populate an instance of the generated user-defined table data type: 要执行存储过程,您想填充一个生成的用户定义表数据类型的实例:

DECLARE @R_MODS R_MODS_TBL

INSERT INTO @R_MODS VALUES ('11-0001','TP');
INSERT INTO @R_MODS VALUES ('11-0002','TP');
INSERT INTO @R_MODS VALUES ('11-0003','TP');
INSERT INTO @R_MODS VALUES ('11-0004','TP');
INSERT INTO @R_MODS VALUES ('11-0005','TP');
INSERT INTO @R_MODS VALUES ('11-0006','I');
INSERT INTO @R_MODS VALUES ('11-0007','TP');
INSERT INTO @R_MODS VALUES ('11-0008','TP');
INSERT INTO @R_MODS VALUES ('11-0009','I');
INSERT INTO @R_MODS VALUES ('11-0010','TP');
INSERT INTO @R_MODS VALUES ('11-0011','TP');
INSERT INTO @R_MODS VALUES ('11-0012','TN');
INSERT INTO @R_MODS VALUES ('11-0013','TP');
INSERT INTO @R_MODS VALUES ('11-0014','I');
INSERT INTO @R_MODS VALUES ('11-0015','TP');
INSERT INTO @R_MODS VALUES ('11-0016','TP');
INSERT INTO @R_MODS VALUES ('11-0017','TN');
INSERT INTO @R_MODS VALUES ('11-0018','TP');
INSERT INTO @R_MODS VALUES ('11-0019','FP');
INSERT INTO @R_MODS VALUES ('11-0020','FP');

EXEC dbo.YourStoredProcedure @R_MODS

SQL Fiddle SQL小提琴


Note: 注意:

When using table valued as an input parameter in a stored procedure, it is required to declare the parameter as READONLY . 在存储过程中使用值表作为输入参数时,需要将参数声明为READONLY Read this answer by Mikael Eriksson for more information. 阅读Mikael Eriksson的答案,以获得更多信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM