sql - 按天均匀分布行

标签 sql t-sql business-intelligence sql-server-2016

我有一个表格,我把它称为手动值,稍后在我的代码中使用。该表如下所示:

subId | MonthNo | PackagesNumber | Country | EntryMethod | PaidAmount | Version
1     | 201701  | 223            | NO      | BCD         | 44803      | 2
2     | 201701  | 61             | NO      | GHI         | 11934      | 2
3     | 201701  | 929            | NO      | ABC         | 88714      | 2
4     | 201701  | 470            | NO      | DEF         | 98404      | 2
5     | 201702  | 223            | NO      | BCD         | 28225      | 2

我所要做的就是在单个包的级别将这些值分成单行。例如,2017 年 1 月,国家/地区 NO 有 223 个包裹,采用 EntryMethod BCD,因此我需要 223 个单独的行。 PaidAmount 还应除以 PackagesNumber 的数量。

问题是我必须将日期与每条记录相关联。记录应在整个月内均匀分布。我有日期维度,我可以通过从 MontNo 中分别提取月份和年份来与我的表格相交。 例如,2017 年 1 月,EntryMethod BCD 我有包裹,所以每天大约有 7 个包裹。

这就是我想要的:

subId | Date       | Country | Packages | EntryMethod | PaidAmount       | Version
1     | 01.01.2017 | NO      | 1        | BCD         | 200.910313901345 | 2
2     | 01.01.2017 | NO      | 1        | BCD         | 200.910313901345 | 2
3     | 01.01.2017 | NO      | 1        | BCD         | 200.910313901345 | 2
4     | 01.01.2017 | NO      | 1        | BCD         | 200.910313901345 | 2
5     | 01.01.2017 | NO      | 1        | BCD         | 200.910313901345 | 2
6     | 01.01.2017 | NO      | 1        | BCD         | 200.910313901345 | 2
7     | 01.01.2017 | NO      | 1        | BCD         | 200.910313901345 | 2
8     | 02.01.2017 | NO      | 1        | BCD         | 200.910313901345 | 2

奖励:我编写了代码,将包划分为单个记录,并将每个月的第一天作为日期。

SELECT
       Date =
(
    SELECT TOP 1
           date
    FROM dim_Date dim
    WHERE dim.Month = a.Month
          AND dim.Year = a.Year
)
     , Country
     , EntryMethod
     , Deliveries = 1
     , PaidAmount = NULLIF(PaidAmount, 0) / PackagesNumber
     , SubscriptionId = 90000000 + ROW_NUMBER() OVER(ORDER BY n.number)
     , Version
FROM
(
    SELECT
           [Year] = LEFT(MonthNo, 4)
         , [Month] = RIGHT(MonthNo, 2)
         , Country
         , EntryMethod
         , PackagesNumber
         , PaidAmount
         , Version
    FROM tgm.rep_PredictionsReport_ManualValues tgm

    /*WHERE MonthNo = 201701*/
) a
JOIN master..spt_values n
ON n.type = 'P'
   AND n.number < CAST(PackagesNumber AS INT);

编辑:我取得了一些进展。我使用 NTILE 函数将行分组。 唯一改变的是顶级选择中的日期。现在看起来像这样:

Date = concat([Year], '-', [Month], '-', case when ntile(31) over(order by n.number) < 10  then '0' + cast(ntile(31) over(order by n.number) as varchar(2)) else cast(ntile(31) over(order by n.number) as varchar(2)) end)

说明:我正在使用字段以及NTILE创建日期归档,超过月份的天数(现在是静态数字,但稍后会更改) 。结果并不像我预期的那样好,它创建的组是应有大小的两倍(每个日期有 14 行而不是 7 行)。

最佳答案

您可以使用模运算符来完成此操作,它允许您将项目分为一定数量的类别。

这是一个完整的测试:http://rextester.com/TOROA96856

以下是相关查询:

--recursive query to expand each row.
with expand_rows (subid,monthno,month,packagesnumber,paidamount) as (
    select subid,monthno,month,packagesnumber,(paidamount+0.0000)/packagesnumber 
       from initial_table
    union all
    select subid,monthno,month,packagesnumber-1,paidamount 
       from expand_rows where packagesnumber >1
)
select expand_rows.*,(packagesnumber % numdays)+1 day, paidamount from expand_rows
    join dayspermonth d on
        d.month = expand_rows.month
    order by subid, day
    option (maxrecursion 0)

(packagesnumber % numdays)+1 是将项目分配给一天的模运算。

请注意,我预先计算了每个月的天数表,以便在查询中使用。为了回答的目的,我还稍微简化了问题(添加了纯月份列,因为我不想复制日期维度)。

如果您关心当事情不均匀分配时额外的项目最终在哪里(例如,如果您在一月份有 32 个项目,哪一天有一个额外的项目?),您可能需要调整模查询。在此示例中,该月的第二天往往获得最多(因为加 1 来说明该月的最后一天最终为 0)。如果您希望额外的天数落在月初,您可以使用 case 语句将 0 转换为该月的天数。

关于sql - 按天均匀分布行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43778404/

相关文章:

reporting-services - 基于 Web 的报告工具(类似于 Tableau)

PHP-Mysql 查询

mysql - 从另一个 SQL 更新表

t-sql - 在这种情况下为什么使用 TIMESTAMP 而不是 DATETIME?

sql - 返回团队成员多次被召回的日期

hadoop - 评估和比较 Hadoop 的商业智能设计注意事项

mysql - 添加新条目时更新星形列直到根节点

java - SQL 错误 : 933, SQLState: 42000 和 ORA-00933: SQL 命令未正确结束

sql - 如何在 T-SQL 中将 int 转换为零填充字符串?

oracle - OBIEE 12.2.1.2 - 数值的自定义数据格式