在where子句中有不同的条件时,如何在这种情况下用join替换子查询?

时间:2015-12-04 05:42:42

标签: sql sql-server sql-server-2008 tsql join

我有两张桌子。 ledTbl_LoanMst

CREATE TABLE [dbo].[led](
    [GLCode] [varchar](10) NOT NULL,
    [AccountID] [varchar](15) NULL,
    [Dr_Cr] [char](1) NOT NULL,
    [amount] [money] NULL,
    [LoanRefNo] [varchar](20) NULL
) ON [PRIMARY]

CREATE TABLE [dbo].[Tbl_LoanMst](
    [SrNo] [int] IDENTITY(1,1) NOT NULL,
    [Acctno] [varchar](15) NULL,
    [LoanTranchNo] [varchar](20) NULL,
    [DisbursalDate] [varchar](8) NULL,
    [LoanStartDate] [varchar](8) NULL,
    [Tenure] [money] NULL,
    [LoanExpiryDate] [varchar](8) NULL,
    [InterestRate] [money] NULL,
    [PenalInterestRate] [money] NULL,
    [IntrFrequency] [char](11) NULL,
    [LoanAmount] [money] NULL,
    [ApplicableDP] [money] NULL,
    [ProcessingFees] [money] NULL,
    [OtherCharges] [money] NULL,
    [Paymode] [varchar](6) NULL,
    [Chq_BankTxnNo] [varchar](15) NULL,
    [CompanyBankID] [varchar](20) NULL,
    [CompanyBankAcctno] [varchar](20) NULL,
    [Cl_BankID] [varchar](10) NULL,
    [Cl_BankAcctno] [varchar](20) NULL,
    [LedgerRefNo] [varchar](20) NULL,
    [Status] [char](1) NULL,
    [uMkrid] [varchar](11) NULL,
    [uMkrdt] [datetime] NULL,
    [aMkrid] [varchar](11) NULL,
    [aMkrdt] [datetime] NULL,
    [BF_Generated] [varchar](5) NULL,
    [bankaccttype] [varchar](20) NULL,
    [LoanType] [varchar](20) NULL
) ON [PRIMARY]

这是我的工作查询。

declare @LasAcctNo varchar(20)  = 'las00004'      

select distinct LoanTranchNo,  convert(varchar,convert(datetime,LoanStartDate),103) LoanStartDate,

(select CONVERT(numeric(18,2),ROUND( sum(amount),2)) from  led where  GLCode = 'LASPAC' and LoanRefNo = LoanTranchNo and Dr_Cr='D' ) as LoanAmount,
(select CONVERT(numeric(18,2),ROUND( sum(amount),2)) from  led where  GLCode = 'LASPAC' and LoanRefNo = LoanTranchNo and Dr_Cr='C' ) PrincipalPaid
, (select CONVERT(numeric(18,2),ROUND( sum(amount),2)) from  led where  GLCode = 'LASPAC' and LoanRefNo = LoanTranchNo) 'OsLoanAmount',
InterestRate,
(select CONVERT(numeric(18,2),ROUND( sum( case when Dr_Cr='C' then amount *-1 else amount  end  ),2)) from  led where GLCode = 'INTRAC' and LoanRefNo = LoanTranchNo)  InterestAccruedDue,
(select CONVERT(numeric(18,2),ROUND( sum(case when Dr_Cr='C' then amount *-1 else amount  end ),2)) from  led where  GLCode = 'PNLINT' and LoanRefNo = LoanTranchNo)  PenalDue ,0 as 'TotalOutstanding',
(select CONVERT(numeric(18,2),ROUND( sum(case when Dr_Cr='C' then amount *-1 else amount  end ),2)) from  led where  GLCode = 'INTRND' and LoanRefNo = LoanTranchNo) InterestAccruedbutnotdue,
(select CONVERT(numeric(18,2),ROUND( sum(case when Dr_Cr='C' then amount *-1 else amount  end ),2)) from  led where  GLCode = 'TDSACC' and LoanRefNo = LoanTranchNo)as  TDS,
(select CONVERT(numeric(18,2),ROUND( sum(case when Dr_Cr='C' then amount *-1 else amount  end ),2)) from  led where  GLCode = 'CLNCTRLAC' and AccountID = Acctno)as  ControlAcct,
convert(varchar,convert(datetime,LoanExpiryDate),103) LoanEndDate,IntrFrequency,isnull(LoanType,'SECURED')  as LoanType
from tbl_loanmst
left join  led on LoanTranchNo= LoanRefNo and AcctNo = AccountID
where AcctNo= @LasAcctNo and status='A'

是否可以使用连接重写此查询?如果是的话怎么样?

为了让您尽可能方便,我在以下链接中包含了insert语句: http://en.textsave.org/mwOb

1 个答案:

答案 0 :(得分:0)

既然您在评论中建议您热衷于学习,而不仅仅是复制,我故意不提供完整的解决方案:-)

在没有子查询的情况下,几乎可以肯定有多种方法可以实现。我赞赏你想要学习另一种选择的愿望,因为在大多数情况下我个人不喜欢子查询(当然是这个)。

您已熟悉在case等聚合函数中使用sum,因此删除子查询的简便方法是扩展该模式。仅挑选一个子查询作为示例:

(select CONVERT(numeric(18,2),ROUND( sum(amount),2)) from  led where  GLCode = 'LASPAC' and LoanRefNo = LoanTranchNo and Dr_Cr='D' ) as LoanAmount,

可以通过将相关的where条件移动到案例陈述中来重写:

,convert(numeric(18,2),round(sum(case when L.GLCode = 'LASPAC' and L.Dr_Cr='D' then amount end),2)) as LoanAmount

因为您可以直接引用led表中的任何列,因为您已经加入了它。此表单中不需要检查LoanRefNo = LoanTranchNo,因为它是两个表之间的主要连接条件的一部分。

部分原因在于,当条件不满足时,新的case语句将为null,因此sum在计算中不会包含nulls

要在更广泛的查询中使用此功能,您需要使用SQL group by子句来允许sum函数在多行上运行。 group by告诉SQL将哪些列组合在一起以生成数字和。

所以,有一个更多上下文的例子:

with cteGroupedData as (
  select          
              T.LoanTranchNo
              ,T.InterestRate
              ,T.IntrFrequency
              ,T.LoanStartDate
              ,T.LoanExpiryDate

              ,sum(case when L.GLCode = 'LASPAC' and L.Dr_Cr='D' then amount end) as LoanAmount

  from        tbl_loanmst    T
  left join   led            L    on T.LoanTranchNo=L.LoanRefNo
                                  and T.AcctNo = L.AccountID
  where         T.Acctno= 'las00004'
  and           T.Status='A'

  group by    T.LoanTranchNo
              ,T.InterestRate
              ,T.IntrFrequency
              ,T.LoanStartDate
              ,T.LoanExpiryDate
  )

select    LoanTranchNo
          ,InterestRate
          ,IntrFrequency
          ,convert(varchar,convert(datetime,LoanStartDate),103)     as LoanStartDate
          ,convert(varchar,convert(datetime,LoanExpiryDate),103)    as LoanEndDate

          ,convert(numeric(18,2),round(LoanAmount,2))             as LoanAmount

from      cteGroupedData

这个例子只是使用了一些列(因为我不得不将其删除以便自己理解),因此您需要将其用作示例并构建回到完整查询。

其他注意事项

我在这里做了一些其他的事情,我将简要地指出:

  • 将主分组步骤分为公用表表达式(CTE) - 这在我看来更清晰,并且意味着数据类型转换可以在以后单独完成。
  • 将表格别名为TL,并在任何地方使用这些别名,因此我很容易知道每列来自哪个表
  • 按照我喜欢的方式展开它 - 个人喜好,但空间是你的朋友!