【问题标题】:SQL SUM on multiple INNER JOIN多个 INNER JOIN 上的 SQL SUM
【发布时间】:2019-02-03 21:36:42
【问题描述】:

我正在尝试使用连接通过多个表获取特定字段的总和。当我尝试将这些值放在一起时,我得到了错误的 SUM。

我有表格状态

| STATE |   MONTH | ID | TOTAL |
--------------------------------
|    FL |    July |  1 | 10000 |
|    CA |   April | 32 |  2000 |

我有另一个表余额作为

| STATE |  Balance|
-------------------
|    FL |      100|
|    FL |      200|
|    CA |      300|
|    CA |      200|
|    CA |      100|

我还有一张桌子贷款

| STATE |     Loan|
-------------------
|    FL |      500|
|    FL |      600|
|    CA |      700|
|    CA |      100|
|    CA |      200|

我想要的查询结果是,

| STATE |     Loan| Balance|
----------------------------
|    FL |     1100|     300|
|    CA |     1000|     600|

当我尝试使用以下查询时,我得到的状态是正确的贷款金额,

SELECT 
  S.STATE, 
  SUM(L.Loan) 
FROM State AS S
  INNER JOIN Loan AS L ON L.STATE = S.STATE
GROUP BY
 S.STATE

我得到以下结果,

| STATE |      Loan|
--------------------
|    FL |      1100|
|    CA |      1000|

同样,我可以从余额表中得到总和。 我想要实现的是使用单个事务从两个表中获取总和。

虽然,我能够得到想要的值,如果我这样做,

SELECT
  STATE AS STATE
  SUM(DataSetB.Balance) AS Balance
FROM
    (
    SELECT 
      STATE AS STATE,
      B.Balance AS Balance
    FROM
        (
        SELECT 
          S.STATE AS STATE, 
          SUM(L.Loan) AS Loan,
        FROM State AS S
          INNER JOIN Loan AS L ON L.STATE = S.STATE
        GROUP BY S.STATE
        )
        AS DataSetL
     INNER JOIN Balance AS B ON B.STATE = DataSetL.STATE
     GROUP BY
       DataSetL.STATE, B.Balance
     ) AS DataSetB
GROUP BY 
  DataSetB.STATE

但是,这在我拥有的大型数据集上不太可行。 我试过了,

SELECT 
  S.STATE AS STATE, 
  SUM(L.Loan) AS Loan,
  SUM(B.Balance) AS Balance
FROM State AS S
  INNER JOIN Loan AS L ON L.STATE = S.STATE
  INNER JOIN Balance AS B ON B.STATE = S.STATE
GROUP BY 
  S.STATE

但这给我的值是实际值的倍数。它实际上是子表中存在的行数的倍数。

我并不是要一个确切的解决方案,但任何类型的指针都会很好。

【问题讨论】:

    标签: sql sql-server join sum inner-join


    【解决方案1】:

    你可以试试这个,使用UNION ALL结合BalanceLoan的表格并使用一点技巧,

    • Balance 填一个Loan 列集0
    • Loan 填一个Balance 列集0

    然后JOINStateSUM

    create table State(
      STATE varchar(50)
    );
    
    
    
    insert into State values ('FL'); 
    insert into State values ('CA'); 
    create table Balance(
      STATE varchar(50),
      Balance int
    );
    
    
    
    insert into Balance values ('FL',100);
    insert into Balance values ('FL',200);
    insert into Balance values ('CA',300);
    insert into Balance values ('CA',200);
    insert into Balance values ('CA',100);
    
    create table Loan(
      STATE varchar(50),
      loan int
    );
    
    insert into loan values ( 'FL',500);
    insert into loan values ( 'FL',600);
    insert into loan values ( 'CA',700);
    insert into loan values ( 'CA',100);
    insert into loan values ( 'CA',200);
    

    查询 1

    SELECT s.STATE,SUM(t1.Loan) as 'Loan',SUM(t1.Balance) as 'Balance'
    FROM 
    (
      SELECT STATE,0 AS Loan,Balance  
      FROM Balance 
      UNION ALL
      SELECT STATE,Loan,0   
      FROM Loan 
    ) t1
    INNER JOIN State s on s.STATE = t1.STATE
    GROUP BY s.STATE
    

    Results

    | STATE | Loan | Balance |
    |-------|------|---------|
    |    CA | 1000 |     600 |
    |    FL | 1100 |     300 |
    

    【讨论】:

    • 这是一个好方法。然而,单引号是字符串文字的分隔符,而不是名称的分隔符。标准 SQL 使用双引号,SQL Server 使用括号,但无论如何您都不需要它们:SUM(t1.Loan) as Loan, SUM(t1.Balance) as Balance
    【解决方案2】:

    在单独的子查询中对每个表进行聚合,然后加入:

    SELECT 
      S.STATE AS STATE, 
      L.Loan,
      B.Balance
    FROM State AS S
      LEFT JOIN (select state, sum(loan) as Loan
                  from loan
                  group by state) AS L ON L.STATE = S.STATE
      LEFT JOIN (select state, sum(Balance) as balance
                  from balance
                  group by state) AS B ON B.STATE = S.STATE
    

    (左连接,以防状态没有贷款或余额行。)

    【讨论】:

    • 嗨@jarlh,我实际上想要这样的东西。谢谢,我试过了,它可以工作,但是响应很慢。对于单个状态,它需要 36 秒,而我共享的方法在 1 秒内得到结果。我认为这是因为贷款和余额表很大,需要时间将它们分组,然后汇总。我尝试在内部查询中添加过滤器,但显然它无法识别 State 表的字段。我将尝试将状态存储在变量中并将其传递给内部查询。也许它会起作用。
    • @Pradumn Kumar Mahanta:jarlh 在这里展示的这种方法应该是最快的。尽管如此,由于您要选择所有现有数据,这需要时间。您可能希望在 loan(state, loan)balance(state, balance) 上创建两个覆盖索引,以便 DBMS 找到已按状态分隔的所有贷款和余额。
    • @Pradumn Kumar Mahanta:如果您需要更快的速度,您可以决定将数据存储在表分区中。见docs.microsoft.com/en-us/sql/relational-databases/partitions/…cathrinewilhelmsen.net/2015/04/12/…
    【解决方案3】:

    你可以试试这个:

    Select S.State, B.Balance,L.Loan from State S 
    inner join (select state, sum(loan) as Loan from Loan group by state) L
    inner join (select state, sum(balance) as Balance from Balance group by state) B
    on L.state=S.state and B.State=S.State;
    

    【讨论】:

    • 对于 SQL Server,每个 INNER JOIN 是否都需要一个自己的 ON 子句?
    【解决方案4】:

    使用子查询:首先连接贷款和余额表,然后将状态表与派生表结果连接

    SELECT 
      S.STATE AS STATE, Loan,Balance
    FROM State AS S inner join
     (select L.state,sum(loan) as loan, sum(balance) as balance
     from Loan AS L INNER JOIN Balance AS B ON B.STATE = S.STATE
     GROUP BY L.STATE)X on s.state=x.state
    

    【讨论】:

      【解决方案5】:

      我建议使用公用表表达式,因为它读起来很“干净”。

      尝试以下方法:

      WITH CTE_TotalLoan AS (
        SELECT
          State,
          SUM(Loan) AS TotalLoan
        FROM Loan
        GROUP BY State
      ),
      
      CTE_TotalBalance AS (
        SELECT
          State,
          SUM(Balance) AS TotalBalance
        FROM Balance
        GROUP BY State
      )
      
      SELECT 
        S.State,
        TotalLoan,
        TotalBalance
      FROM State AS S
      INNER JOIN CTE_TotalLoan AS L ON L.STATE = S.STATE
      INNER JOIN CTE_TotalBalance AS B ON B.STATE = S.STATE
      

      working SQL Fiddle

      【讨论】:

        【解决方案6】:

        试试这个:

        SELECT S.STATE, L.Loan as TotalLoan, B.Balance as TotalBalance
        FROM State AS S
        LEFT JOIN (select STATE, sum(Loan) as Loan
                   from Loan
                   group by STATE) AS L
        ON L.STATE = S.STATE
        
        LEFT JOIN (select STATE, sum(Balance) as Balance
                   from Balance
                   group by STATE) AS B
        ON B.STATE = S.STATE
        

        结果是:

        | STATE |TotalLoan|TotalBalance|
        ----------------------------
        |    FL |   1100  |     300    |
        |    CA |   1000  |     600    |
        

        【讨论】:

          【解决方案7】:

          试试这个:

                  Create Table #Loan([State] Varchar(10),Loan Bigint)
                  Create Table #Balance([State] Varchar(10),Balance Bigint)
          
                  Insert Into #Loan
                  Select 'FL',500 Union All
                  Select 'FL',600 Union All
                  Select 'CA',700 Union All
                  Select 'CA',100 Union All
                  Select 'CA',200
          
                  Insert Into #Balance
                  Select 'FL',100 Union All
                  Select 'FL',200 Union All
                  Select 'CA',300 Union All
                  Select 'CA',200 Union All
                  Select 'CA',100 
          
                  ;with cteLoan
                  AS(
                      Select ROW_NUMBER() Over(Partition by State order by State) As Rn, * from #Loan
                  )
                  ,
                  cteBalance
                  AS(
                      Select ROW_NUMBER() Over(Partition by State order by State) As Rn, * from #Balance
                  )
          
          
                  Select DISTINCT ISNULL(l.State,b.State) as State
                  ,SUM(ISNULL(Loan,0)) As Loan
                  ,SUM(ISNULL(Balance,0)) As Balance
                  from cteLoan l
                  FULL OUTER JOIN cteBalance b
                  on l.State=b.State and l.rn=b.rn
                  Group by ISNULL(l.State,b.State)
          
                  Drop Table #Loan
                  Drop Table #Balance
          

          【讨论】:

            【解决方案8】:

            你也可以使用APPLY

            SELECT s.*, l.loan, b.balance 
            FROM State s OUTER APPLY
                 (SELECT SUM(l.loan) loan
                  FROM loan l
                  WHERE l.state = s.state
                 ) l OUTER APPLY 
                 (SELECT SUM(b.balance) balance 
                  FROM balance b
                  WHERE b.state = s.state
                 ) b;
            

            【讨论】:

              猜你喜欢
              • 2011-03-03
              • 2014-01-22
              • 2021-11-21
              • 1970-01-01
              • 2014-02-24
              • 1970-01-01
              • 2018-06-12
              相关资源
              最近更新 更多