带有过滤器的复杂表联接,并对列使用“赞”

时间:2018-08-20 21:42:22

标签: sql-server

我有一个复杂的表,其中显示了销售信息的实际和预测以及多个上载日期。我希望能够在产品ID上加入表,同时查找每个产品的错误百分比,并且仅使用最新信息。这些产品来自众多供应商,因此它们都有不同的名称,但涉及同一产品。例如,来自两个供应商的产品A的名称可能是Supplier1_A和Supplier2_A,但是我希望能够将它们一起添加到一栏中以查找错误。这是数据示例:

Type     | ID                | DateUpload     |Jan. | Feb. | March
Forecast   Supplier1_Apples       2018-01-01    5      6      5
Actual     Supplier1_Apples       2018-01-01    4      4      5
Forecast   Supplier1_Apples       2018-02-01    5      6      5
Actual     Supplier1_Apples       2018-02-01    4      6      5
Forecast   Supplier2_Apples       2018-02-01    6      6      5
Actual     Supplier2_Apples       2018-02-01    4      4      3
Forecast   Supplier3_Apples       2018-02-01    8      9      5
Actual     Supplier3_Apples       2018-02-01    7      8      5

我最后想要的表看起来像这样

ID    | DateUpload  | error_jan...
Apples   2018-02-01   (abs(total_actual - total_forecast))/total_actual

此联接是否可以与所有过滤器合并到一个表中?或者我需要创建一个不同的表来获取每个供应商的错误,然后求出平均值吗?目前,我能够基于ID联接表以查找每个ID处的错误,但是在本示例中,如果它们相似以查找苹果的整体错误,则无法将它们全部合并。

2 个答案:

答案 0 :(得分:1)

  • 您需要拆分ID以从ID中删除供应商
  • 然后使用CTE或子查询过滤掉实际数据和预测数据
  • 然后在ID和DateUploaded上同时加入CTE
  • 然后按ID和DateUploaded分组
  • 现在您知道如何计算“错误”列的值了,我为JAN做到了,希望它能工作。

数据准备

declare @mytable as table(
Type varchar(10),
ID varchar(50),
DateUploaded datetime,
JAN decimal
)

insert into @mytable values ('Forecast', 'Supplier1_Apples','2018-01-01',5)
insert into @mytable values ('Actual', 'Supplier1_Apples','2018-01-01',4)

insert into @mytable values ('Forecast', 'Supplier1_Apples','2018-02-01',5)
insert into @mytable values ('Actual', 'Supplier1_Apples','2018-02-01',4)

insert into @mytable values ('Forecast', 'Supplier2_Apples','2018-02-01',6)
insert into @mytable values ('Actual', 'Supplier2_Apples','2018-02-01',4)

insert into @mytable values ('Forecast', 'Supplier3_Apples','2018-02-01',8)
insert into @mytable values ('Actual', 'Supplier3_Apples','2018-02-01',7)

查询:

;With ForecastCTE AS
(
    Select 
    substring(ID, CHARINDEX('_',ID)+1, LEN(ID)) as Id, 
    DateUploaded,
    JAN
    From @mytable
    Where Type = 'Forecast'
),
ActualCTE AS
(
    Select 
    substring(ID, CHARINDEX('_',ID)+1, LEN(ID)) as Id, 
    DateUploaded,
    JAN
    From @mytable
    Where Type = 'Actual'
)
Select 
    F.Id,
    F.DateUploaded,
    (abs((SUM(A.JAN) - SUM(F.JAN))/SUM(A.JAN))) AS error_jan
from ForecastCTE F
INNER join ActualCTE A on F.ID = A.ID and F.DateUploaded = A.DateUploaded
Group by F.Id,F.DateUploaded

输出:

Id      DateUploaded                error_jan
Apples  2018-01-01 00:00:00.000     0.250000
Apples  2018-02-01 00:00:00.000     0.266666

答案 1 :(得分:0)

如果要使用固定模式,则可以加入或分组任何产品。例如,在您的示例Supplier1_Apples中,我们可以看到所有产品Apples的前缀都带有SupplierID以及(下划线)作为分隔符。供应商名称和产品名称可以更改,但是(下划线)将全部使用。在这种情况下,我们可以使用CHARINDEX()函数来获取该产品的位置编号(下划线),这将有助于我们仅提取产品ID。

因此,为此,我们将使用CHARINDEX()LEN()SUBSTRING()函数具有类似以下内容:

SUBSTRING(ID, CHARINDEX('_',ID,1) + 1,LEN(ID) - CHARINDEX('_',ID,1) + 1)

这将给我们Apples,这是我们的目标。 从那里,我们可以将GROUP BYSUM()一起使用,将结果分组如下:

SELECT 
  [Type]
, SUBSTRING(ID, CHARINDEX('_',ID,1) + 1,LEN(ID) - CHARINDEX('_',ID,1) + 1) ID
, DateUpload
, SUM(Jan) Jan
, SUM(Feb) Feb
, SUM(Mar) Mar
FROM test
GROUP BY 
 [Type]
, SUBSTRING(ID, CHARINDEX('_',ID,1) + 1,LEN(ID) - CHARINDEX('_',ID,1) + 1)
, DateUpload

这将给我们:

|     Type |     ID | DateUpload | Jan | Feb | Mar |
|----------|--------|------------|-----|-----|-----|
|   Actual | Apples | 2018-01-01 |   4 |   4 |   5 |
|   Actual | Apples | 2018-02-01 |  15 |  18 |  13 |
| Forecast | Apples | 2018-01-01 |   5 |   6 |   5 |
| Forecast | Apples | 2018-02-01 |  19 |  21 |  15 |

现在,仅将它用作子查询就可以了,您可以从那里走得更远。

一个例子:

SELECT 
  ID
, DateUpload 
, error_jan     =   ( ABS(TotalJunActual -  TotalJunForecast) ) / TotalActual
FROM (
SELECT 
    ID 
,   DateUpload
,   SUM(ABS(CASE WHEN [Type] = 'Actual' THEN JAN ELSE 0 END)) TotalJunActual
,   SUM(ABS(CASE WHEN [Type] = 'Forecast' THEN JAN ELSE 0 END)) TotalJunForecast
,   SUM(ABS(CASE WHEN [Type] = 'Actual' THEN JAN + Feb + Mar  ELSE 0 END)) TotalActual
,   SUM(ABS(CASE WHEN [Type] = 'Forecast' THEN JAN + Feb + Mar ELSE 0 END)) TotalForecast
FROM (
SELECT 
  [Type]
, SUBSTRING(ID, CHARINDEX('_',ID,1) + 1,LEN(ID) - CHARINDEX('_',ID,1) + 1) ID
, DateUpload
, SUM(Jan) Jan
, SUM(Feb) Feb
, SUM(Mar) Mar
FROM test
GROUP BY 
 [Type]
, SUBSTRING(ID, CHARINDEX('_',ID,1) + 1,LEN(ID) - CHARINDEX('_',ID,1) + 1)
, DateUpload
) D
GROUP BY 
    ID 
,   DateUpload
) C

结果:

|     ID | DateUpload | error_jan |
|--------|------------|-----------|
| Apples | 2018-01-01 |  0.076923 |
| Apples | 2018-02-01 |  0.086956 |

Fiddle Demo