我如何按查询结果对表本身进行分组?

时间:2019-01-02 17:26:29

标签: tsql

我有一个混乱的报告,它是用意大利面条式编码建立的,执行100个SQL请求,并使客户端陷入困境。我正在重写它,但是我的SQL感觉就像一团糟。

我觉得我缺少按键操作...

该报告显示发票数,发票总数,发票类型以及基于当月,上个月,本年度和上一年的累计金额的过滤器分组。

为简单起见,假设所有发票价值100美元,并且在2017年和2018年每个地区(12月以外)每种类型的发票都有10张。

因此,如果我获得12月份的报告,则需要这样的内容:

 type  || description  || location || 2017-DEC || 2018-DEC || 2017-CUMUL  || 2018-CUMUL
-------------------------------------------------------------------------------------------
type A || descr. 'a'   || town 1   ||    1     ||    3    ||    1100$     || 1300$
type B || descr. 'b    || town 1   ||    2     ||    4    ||    1200$     || 1400$

任何人都可以发现我在这里做错了什么吗?合并感觉就像是清理由于错误使用完整外部联接而造成的混乱...

这是我到目前为止的查询:

select a.type
, a.desc
, a.area
, sum(a.prec_InvoiceNumber)
, sum(a.InvoiceNumber)
, sum(a.yprec_amount)
, sum(a.ycurr_amount)
 from ( 
    SELECT coalesce(CURR.type,prec.type, yprec.type,YCurr.type) as type
    , coalesce(CURR.desc,prec.desc, yprec.desc,YCurr.desc) as desc
    , coalesce(CURR.area,prec.area, yprec.area,YCurr.area) as area
    , isnull(PREC.InvoiceNumber,0) as prec_InvoiceNumber
    , isnull(CURR.InvoiceNumber,0) as InvoiceNumber
    , isnull(YPREC.amount,0) as YPREC_amount
    , isnull(YCurr.amount,0) as YCurr_amount 
    from 
    (
        SELECT invoice.type 
        , invoiceType.desc
        , locationarea.desc as area
        , Count(INVOICE.IDNumber) as InvoiceNumber,
        , SUM(Invoice.amount) as amount
        FROM Invoice
        left join invoicteype on invoice.type = invoicetype.type
        left join locationarea on locationarea.Id = invoice.locationID
        Where Invoice.date between '2017-12-01' and '2017-12-31'
        and invoicetype.type in ('a','b')
        and locationarea.ID = 1
         group by Invoice.type, locationarea.desc, invoiceType.desc
    ) PREC
    FULL OUTER JOIN (
        SELECT invoice.type 
        , invoiceType.desc
        , locationarea.desc as area
        , Count(INVOICE.IDNumber) as InvoiceNumber,
        , SUM(Invoice.amount) as amount
        FROM Invoice
        left join invoicteype on invoice.type = invoicetype.type
        left join locationarea on locationarea.Id = invoice.locationID
        Where Invoice.date between '2018-12-01' and '2018-12-31'
        and invoicetype.type in ('a','b')
        and locationarea.ID = 1
        group by Invoice.type, locationarea.desc, invoiceType.desc
    ) CURR ON PREC.type= CURR.type AND PREC.area= CURR.area AND PREC.desc= CURR.desc
    FULL OUTER JOIN (
        SELECT invoice.type 
        , invoiceType.desc
        , locationarea.desc as area
        , Count(INVOICE.IDNumber) as InvoiceNumber,
        , SUM(Invoice.amount) as amount
        FROM Invoice
        left join invoicteype on invoice.type = invoicetype.type
        left join locationarea on locationarea.Id = invoice.locationID
        Where Invoice.date between '2017-01-01' and '2017-12-31'
        and invoicetype.type in ('a','b')
        and locationarea.ID = 1
        group by Invoice.type, locationarea.desc, invoiceType.desc
    ) YPREC ON CURR.type= YPREC.type AND CURR.area= YPREC.area AND CURR.desc= YPREC.desc
    FULL OUTER JOIN (
        SELECT invoice.type 
        , invoiceType.desc
        , locationarea.desc as area
        , Count(INVOICE.IDNumber) as InvoiceNumber,
        , SUM(Invoice.amount) as amount
        FROM Invoice
        left join invoicteype on invoice.type = invoicetype.type
        left join locationarea on locationarea.Id = invoice.locationID
        Where Invoice.date between '2018-01-01' and '2018-12-31'
        and invoicetype.type in ('a','b')
        and locationarea.ID = 1
        group by Invoice.type, locationarea.desc, invoiceType.desc
    ) YCURR ON CURR.type= YCURR .type AND CURR.area= YCURR.area AND CURR.desc= YCURR.desc
) a 
group by a.type, a.desc, a.area

编辑:

我很高兴摆脱最后的“选择”和所有合并,我敢肯定有一种更干净的方法可以做到这一点。

自从我创建完全外部联接的方式以来,它们都在第一个子查询('PREC')上联接,因此,如果发票类型存在于2018年,而2017年不存在,那么我的结果会有些混乱('因此,“合并的笨拙用法,以及围绕主“选择”和完整外部联接子查询的“选择a。”)

在我的脑海中应该有一种更简单的写法:

select type, descr, location, count(a.id), count(b.Id), sum(c.value), sum(d.value) 
from TypeTable 
join locationtable  
join descriptiontable
join invoice a 
join invoice b
join invoice c
join invoice d 
where a.date between U and V 
and b.date between W and X
and c.date between U and Y
and d.date between W and z
and type = 'a' 
and description = 'descr a' 
and location = 'town 1'

无需添加所有这些合并和子查询,但是我找不到解决方法。

2 个答案:

答案 0 :(得分:1)

尝试一下... 声明@monthtoview int SET @ monthtoview = 12 ;与acummyear AS(  SELECT invoice.type

    , locationID as area
   -- , INVOICE.IDNumber as InvoiceNumber
    ,year( dbo.Invoice.[date]) AS [year]
    ,month( dbo.Invoice.[date]) AS [month]
    , SUM(Invoice.amount) OVER (PARTITION BY dbo.Invoice.type, year( dbo.Invoice.[date]) ) as amountyear
    ,Invoice.amount AS amountmonth
    FROM Invoice

    Where Invoice.date> '2016-12-31' and Invoice.date<= '2018-12-31' -- years 2017 and 2018
    AND locationID = 1
    AND type IN (1,2)
    )

SELECT type,a.area,a.[year],a.[month]
,count(a.type) as invoicecount
,max(a.amountyear) AS amountperyear
,sum(a.amountmonth) AS amountpermonth
 from  acummyear a --join here your type and location tables
 WHERE a.[month]=@monthtoview 
  GROUP BY type,a.area,a.[year],a.[month]

但是在您的报告(ssrs)中,使用矩阵显示值,您的行将是类型和位置,并且您的列是...一个年份(20XX-CUMUL),其中valueperyear为值,另一个为年份/ month(20XX-DEC),其中有发票计数值,请删除添加到单元格中值的“和”。

答案 1 :(得分:0)

如果我理解正确的话,看来在不同的联接子查询中要处理的主要区别是日期范围。为了即使在特定日期不同的情况下也能够合并来自单个日期范围的结果,您可以尝试使用CASE表达式为同一日期范围内的所有行返回相同的值。例如,您可以使用CASE表达式返回该范围内任何日期的日期范围的开始。或者,如果您不在乎实际的日期值,而只想将其分类到单独的组中,则分配任意数字。

SELECT a.description, invoice_sum
FROM (
SELECT description, sum(a.InvoiceNumber) invoice_sum,
       CASE WHEN date between U and V then 1
            WHEN date between W and X then 2
            WHEN date between U and Y then 3
            WHEN date between W and Z then 4
       ELSE 5 END dategroup
FROM Invoice
) a
GROUP BY a.dategroup, a.description