【问题标题】:How can I join on a stored procedure?如何加入存储过程?
【发布时间】:2010-10-29 14:27:57
【问题描述】:

我有一个不带参数的存储过程,它返回两个字段。存储过程汇总了应用于租户的所有事务,并返回余额和租户 ID。

我想使用它通过查询返回的记录集,我需要将它的结果加入到租户的 id 中。

这是我当前的查询:

SELECT t.TenantName, t.CarPlateNumber, t.CarColor, t.Sex, t.SSNO, t.Phone, t.Memo,
        u.UnitNumber,
        p.PropertyName
FROM tblTenant t
    LEFT JOIN tblRentalUnit u
    ON t.UnitID = u.ID

    LEFT JOIN tblProperty p
    ON u.PropertyID = p.ID

ORDER BY p.PropertyName, t.CarPlateNumber

存储过程是这样的:

SELECT tenant.ID AS TenantID, SUM(ISNULL(trans.Amount,0)) AS TenantBalance FROM tblTenant tenant
    LEFT JOIN tblTransaction trans
    ON tenant.ID = trans.TenantID
    GROUP BY tenant.ID

我也想将存储过程中的余额添加到其中。

我该怎么做?

【问题讨论】:

  • 你的问题和你的示例代码没有捆绑在一起——你谈论交易和用户;样本是关于租户和出租物业的。
  • 租户 = 用户。我想在查询中添加余额,因为它是用于报告,并且它还需要有关租户居住的财产的所有信息。
  • 另外,为什么要在出租单元和属性表之间使用 LEFT OUTER JOIN?您不应该让您的数据库处于可能需要它的引用不完整状态(您应该在出租单元和财产之间有一个外键约束,以防止出租单元中的无效代码)。
  • 抱歉,打错了。谢谢你抓住那个。这些表格链接租户 -> 出租单元 -> 财产。
  • 您对 SP 的描述暗示它返回一行 - 但我从进一步的讨论中得到它为每个租户返回一个包含一行的结果集。实际上,它返回一个表。由于您使用的是 SQL Server,我不知道是否有办法让它将来自 SP 的结果集视为表。在至少一个其他 DBMS 中,您可以使用 TABLE(MULTISET(EXECUTE FUNCTION spname())) AS Alias(Balance, ID) 作为 FROM 子句的一部分。

标签: sql sql-server-2005-express


【解决方案1】:

将SP的结果插入到临时表中,然后加入:

CREATE TABLE #Temp (
    TenantID int, 
    TenantBalance int
)

INSERT INTO #Temp
EXEC TheStoredProc

SELECT t.TenantName, t.CarPlateNumber, t.CarColor, t.Sex, t.SSNO, t.Phone, t.Memo,
    u.UnitNumber, p.PropertyName
FROM tblTenant t
INNER JOIN #Temp ON t.TenantID = #Temp.TenantID
...

【讨论】:

    【解决方案2】:

    我实际上喜欢上一个答案(不要使用 SP),但是如果您由于某种原因与 SP 本身相关联,您可以使用它来填充临时表,然后加入临时表。请注意,您将在那里花费一些额外的开销,但这是我能想到的使用实际存储过程的唯一方法。

    同样,最好将来自 SP 的查询内联到原始查询中。

    【讨论】:

    • 我宁愿不内联它,因为如果我确实改变了 SP,我将不得不在我内联它的所有地方寻找并改变它
    • @Malfist,如果你坚持它是一个 SP 而不是一个函数或内联,你唯一的选择就是 AllenG 建议的,填充一个临时表并加入它。
    • 尝试使用表变量而不是临时表。
    • @AllenG 很抱歉,但这不是答案。 “不要使用 SP”是在避免使用 CROSS APPLY 来做这件事,但如果这不起作用,那么答案应该是简单的“不,你不能这样做”。句号。说避免SP,把逻辑改成函数不是答案
    【解决方案3】:

    简短的回答是“你不能”。您需要做的是使用子查询,或者您可以将现有的存储过程转换为表函数。将其创建为函数将取决于您需要它的“可重用性”程度。

    【讨论】:

    • 返回表格的 UDF(用户定义函数)将非常有用。
    • 您说使用“子查询”。那么这不是一个解决方案吗?请用一些代码解释你的意思?谢谢
    【解决方案4】:

    您的存储过程可以很容易地用作视图。然后你可以将它加入到你需要的任何其他东西上。

    SQL:

    CREATE VIEW vwTenantBalance
    AS
    
     SELECT tenant.ID AS TenantID, SUM(ISNULL(trans.Amount,0)) AS TenantBalance 
     FROM tblTenant tenant
     LEFT JOIN tblTransaction trans
     ON tenant.ID = trans.TenantID
     GROUP BY tenant.ID
    

    你可以做任何这样的声明:

    SELECT t.TenantName, t.CarPlateNumber, t.CarColor, t.Sex, t.SSNO, t.Phone, 
        t.Memo, u.UnitNumber, p.PropertyName, TenantBalance
    FROM tblTenant t
    LEFT JOIN tblRentalUnit u
     ON t.UnitID = u.ID
    LEFT JOIN tblProperty p
     ON u.PropertyID = p.ID
    LEFT JOIN vwTenantBalance v 
     ON t.ID = v.tenantID
    ORDER BY p.PropertyName, t.CarPlateNumber
    

    【讨论】:

    • 我想你会发现这是一个比使用临时表更好的答案,因为它仍然是一段集中的代码,只需要在一个地方更新,并且没有开销创建一个临时表,然后插入其中,然后从中选择。
    【解决方案5】:

    我解决了这个问题,编写函数而不是过程,并在 SQL 语句中使用 CROSS APPLY。此解决方案适用于 SQL 2005 及更高版本。

    【讨论】:

      【解决方案6】:

      已经回答了,最好的解决方法是将存储过程转换为 SQL 函数或视图。

      简短的回答是,您不能直接在 SQL 中加入存储过程,除非您使用存储过程的输出创建另一个存储过程或函数到临时表中并加入临时表。

      我将通过将您的存储过程转换为 SQL 函数来回答这个问题,并向您展示如何在您选择的查询中使用它。

      CREATE FUNCTION fnMyFunc()
      RETURNS TABLE AS
      RETURN 
      (
        SELECT tenant.ID AS TenantID, 
             SUM(ISNULL(trans.Amount,0)) AS TenantBalance 
        FROM tblTenant tenant
          LEFT JOIN tblTransaction trans ON tenant.ID = trans.TenantID
        GROUP BY tenant.ID
      )
      

      现在在您的 SQL 中使用该函数...

      SELECT t.TenantName, 
             t.CarPlateNumber, 
             t.CarColor, 
             t.Sex, 
             t.SSNO, 
             t.Phone, 
             t.Memo,
             u.UnitNumber,
             p.PropertyName
      FROM tblTenant t
          LEFT JOIN tblRentalUnit u ON t.UnitID = u.ID
          LEFT JOIN tblProperty p ON u.PropertyID = p.ID
          LEFT JOIN dbo.fnMyFunc() AS a
               ON a.TenantID = t.TenantID
      ORDER BY p.PropertyName, t.CarPlateNumber
      

      如果您希望从上述 SQL 中将参数传递给您的函数,那么我建议您使用 CROSS APPLYCROSS OUTER APPLY

      阅读here

      干杯

      【讨论】:

        【解决方案7】:

        我希望你的存储过程没有做游标循环!

        如果没有,请从您的存储过程中获取查询并将该查询集成到您在此处发布的查询中:

        SELECT t.TenantName, t.CarPlateNumber, t.CarColor, t.Sex, t.SSNO, t.Phone, t.Memo,
                u.UnitNumber,
                p.PropertyName
                ,dt.TenantBalance
        FROM tblTenant t
            LEFT JOIN tblRentalUnit u ON t.UnitID = u.ID
            LEFT JOIN tblProperty   p ON u.PropertyID = p.ID
            LEFT JOIN (SELECT ID, SUM(ISNULL(trans.Amount,0)) AS TenantBalance
                           FROM tblTransaction
                           GROUP BY tenant.ID
                      ) dt ON t.ID=dt.ID
        ORDER BY p.PropertyName, t.CarPlateNumber
        

        如果您在存储过程中执行的不仅仅是查询,请创建一个临时表并将存储过程执行到该临时表中,然后在您的查询中加入该表。

        create procedure test_proc
        as
          select 1 as x, 2 as y
          union select 3,4 
          union select 5,6 
          union select 7,8 
          union select 9,10
          return 0
        go 
        
        create table #testing
        (
          value1   int
          ,value2  int
        )
        
        INSERT INTO #testing
        exec test_proc
        
        
        select
          *
          FROM #testing
        

        【讨论】:

        • 我在问如何集成SP,因为我不知道如何
        • 我相信 SP 正在做一个游标循环
        【解决方案8】:

        这对你来说是个糟糕的主意。

        使用别名,创建一个新的链接服务器,从您的服务器到它自己的别名。

        现在你可以这样做了:

        select a.SomeColumns, b.OtherColumns
        from LocalDb.dbo.LocalTable a
        inner join (select * from openquery([AliasToThisServer],'
        exec LocalDb.dbo.LocalStoredProcedure
        ') ) b
        on a.Id = b.Id
        

        【讨论】:

        • 好可怕的主意,我从来没想过
        • 我们采取这种解决方案的风险是什么?
        【解决方案9】:

        为什么不在你的 SQL 中执行计算?

        SELECT 
          t.TenantName
          , t.CarPlateNumber
          , t.CarColor
          , t.Sex
          , t.SSNO
          , t.Phone
          , t.Memo
          , u.UnitNumber
          , p.PropertyName
          , trans.TenantBalance
        FROM tblTenant t
             LEFT JOIN tblRentalUnit u ON t.UnitID = u.ID
             LEFT JOIN tblProperty p ON u.PropertyID = p.ID
             INNER JOIN (
               SELECT tenant.ID AS TenantID, SUM(ISNULL(trans.Amount,0)) AS TenantBalance 
               FROM tblTenant tenant
                    LEFT JOIN tblTransaction trans ON tenant.ID = trans.TenantID
               GROUP BY tenant.ID
             ) trans ON trans.ID = t.ID
        ORDER BY 
          p.PropertyName
          , t.CarPlateNumber
        

        【讨论】:

          猜你喜欢
          • 2012-09-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-10-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-11-02
          相关资源
          最近更新 更多