【问题标题】:How to replace sub query with join in this case when there are different conditions in where clause?当where子句中有不同的条件时,如何用join替换子查询?
【发布时间】:2015-12-04 05:42:42
【问题描述】:

我有两张桌子。 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'

是否可以使用联接重写此查询?如果是怎么办?

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

【问题讨论】:

  • 嗨。您已经在使用联接。您能否告诉我们您正在尝试解决什么问题,或者是总体风格改进,还是...?
  • @wwkudu 我只是想通过这样做来学习。我想知道如果我能够将这个select column1, (select ......) as column2 from table... 重写为select column1, table.column2 from table join table2 是否会带来任何性能改进,即使没有性能改进我仍然想学习一种新风格。
  • 酷。进行连接的两种方式是select columns from t1, t2 where t1.foreign_key=t2.primary_keyselect columns from t1 left join t2 on t1.foreign_key=t2.primary_key。在大多数数据库中,它们的性能相当。当然,它们不必只是外键和主键。您已经在使用后者。如果我想得直,前者只是一个内部连接。后者有更多的选择,一个解释哪个的图表,是here
  • 您可以嵌套 CASE 以消除子查询。
  • @SubqueryCrunch 怎么样?

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


【解决方案1】:

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

几乎可以肯定有多种方法可以在没有子查询的情况下实现;我赞扬您学习替代方法的愿望,因为我个人在大多数情况下不喜欢子查询(当然是这种情况)。

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

(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,并在各处使用这些别名,因此我很容易知道每列来自哪个表
  • 按我喜欢的方式隔开 - 个人喜好,但空间是你的朋友!

【讨论】:

    猜你喜欢
    • 2020-05-31
    • 2012-06-11
    • 2021-10-14
    • 2014-02-07
    • 1970-01-01
    • 2018-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多