SQL Server:连接数据但在单行中

Posted

技术标签:

【中文标题】SQL Server:连接数据但在单行中【英文标题】:SQL Server: join data but in single row 【发布时间】:2021-08-10 13:01:10 【问题描述】:

我有一张表Invoice,看起来类似于:

order_id completed_at subtotal discount_amount handling_amount
100 07/01/2021 10.09 0 0
101 07/04/2021 200.30 0 0
102 07/04/2021 54.10 0 0
103 07/06/2021 12.00 0 0

我还有一张桌子InvoiceDetail

order_id product_id qty amount
100 1234 1 1.09
100 Shipping1 1 4.30
100 SalesTax 1 .67
101 987 2 74.20
101 654 1 6.20
101 Shipping2 1 5.10
101 SalesTax 1 2.30
102 123 1 30.15
102 Shipping8 1 6.80
102 SalesTax 1 1.08
103 321 1 8.04
103 Shipping4 1 2.05
103 SalesTax 1 .70

我需要加入表格,如下所示:

order_id completed_at subtotal shipping sales_tax discount_amount handling_amount
100 07/01/2021 10.09 4.30 .67 0 0
101 07/04/2021 200.30 5.10 2.30 0 0
102 07/04/2021 54.10 6.80 1.08 0 0
103 07/06/2021 12.00 2.05 .70 0 0

我尝试了几种不同的方法,但每次都以每个 order_id 多行结束。

SELECT 
    order_id,
    completed_at,
    subtotal,
    CASE 
        WHEN t2.product_id LIKE '%Shipping%'
            THEN t2.amount 
    END AS shipping,
    CASE 
        WHEN t2.product_id = 'SalesTax'
            THEN t2.amount 
    END AS sales_tax,
    discount_amount,
    handling_amount
FROM 
    Invoice t1
INNER JOIN 
    InvoiceDetail t2 ON t1.order_id = t2.InvoiceDetail
WHERE 
    order_id BETWEEN '100' AND '103'

上面将输出信息,但每个order_id 都在多行中。我需要将订单信息与运费和销售税结合在一起。如何实现我的目标?

【问题讨论】:

如果可以的话,您可能需要重新考虑您的表架构。如果您将诸如运费和销售税之类的内容转换为单个实际产品的列,我认为您的时间会轻松得多。我希望那些只会有 1 的数量,因此您不仅会使您的查询更加困难,而且您还增加了额外的处理能力来计算您应该存储的值。 您可以为每一列执行左连接,或者 PIVOT 是您要查找的关键字 【参考方案1】:

您已经很接近了,您只需要在InvoiceDetail 的字段周围使用SUM(),然后在Invoice 的字段周围使用GROUP BY

SELECT  i.order_id,
        i.completed_at,
        i.subtotal,
        SUM(CASE WHEN id.product_id LIKE '%Shipping%' THEN id.Amount END) AS shipping,
        SUM(CASE WHEN id.product_id = 'SalesTax' THEN id.Amount END) AS sales_tax,
        i.discount_amount,
        i.handling_amount
FROM    dbo.Invoice AS i
        INNER JOIN dbo.InvoiceDetail AS id
            ON id.order_id = i.order_id
WHERE   i.order_id BETWEEN 100 AND 103
GROUP BY i.order_id, i.completed_at, i.subtotal, i.discount_amount, i.handling_amount;

注意,我从 t1.order_id = t2.InvoiceDetail 更新了您的连接条件,因为这看起来像是问题中的错误,可能是两个表中的 order_id

我还删除了 100103 周围的引号。如果order_id 是整数,则不需要引号,如果order_id 不是整数,则BETWEEN 可能不适合使用。

与您的问题无关,但是对于 SQL Server,养成always including the schema prefix 的习惯是一个好主意(除了您真正想根据执行上下文切换架构的情况)。另一个好习惯是use meaningful table aliases。如果您使用t1t2t3 等,当您有大量查询时,这很快就会变得非常混乱,t4 不会给我任何关于它可能是哪个表的信息,但是如果您使用与表本身(例如,i 用于发票,id 用于发票详细信息),然后在阅读代码时更清楚哪一列来自哪个表。

【讨论】:

【参考方案2】:

您可以在SUM() 聚合函数中使用CASE 来使用条件聚合。例如:

select
  i.order_id,
  max(i.completed_at) as completed_at,
  max(i.subtotal) as subtotal,
  sum(case when d.product_id like 'Shipping%' then amount end) as shipping,
  sum(case when d.product_id = 'SalesTax' then amount end) as sales_tax,
  max(i.discount_amount) as discount_amount,
  max(i.handling_amount) as handling_amount
from invoice i
left join invoicedetail d on d.order_id = i.order_id
group by i.order_id

【讨论】:

以上是关于SQL Server:连接数据但在单行中的主要内容,如果未能解决你的问题,请参考以下文章

Microsoft SQL Server 查询连接数和关闭连接数

如何查看SQL SERVER数据库当前连接数

vs 或 Sql server2012连接Sql server时出现的问题:已成功与服务器建立连接,但在登陆过程中发生错误

vs 或 Sql server2012连接Sql server时出现的问题:已成功与服务器建立连接,但在登陆过程中发生错误

vs 或 Sql server2012连接Sql server时出现的问题:已成功与服务器建立连接,但在登陆过程中发生错误

SSIS 在不使用 SQL 的情况下将多行合并并连接成单行