【问题标题】:TSQL Group/Split Together in Multiple of X based on Variable Column Values基于可变列值的 TSQL 组合/拆分为 X 的倍数
【发布时间】:2018-01-29 23:30:10
【问题描述】:

我希望根据“Drv_uniqId”对以下数据集进行分组或拆分。

Drv_uniqIdTrk_uniqId 之间的关系可以是一对二或一对多(最多 10 个)。也就是说,一个Drv_uniqId最多可以分配给10个Trk_uniqId

Trk_uniqIdDrv_uniqId 之间的关系可以是一对二一或一对二多(最多 4 个)。也就是说,一个Trk_uniqId最多可以分配给4个Drv_uniqId

数据可以包含所有唯一的 Drv_uniqIdTrk_uniqId 组合。我要在报告中显示这些数据,我不能在每一页上显示一行。 Group/split 将在 SSRS 中用于将最终报告拆分为多个页面。

规则

每个Drv_uniqId 必须在同一个组内。不能分成多个组。

每组 = 最少 5 行,最多 10 行

DDL

SELECT *
FROM (VALUES
(1,530,'4392 T_01'),
(2,540,'4209 H_01'),
(3,540,'4551 T_01'),
(4,543,'4407 T_01'),
(5,543,'4691 T_01'),
(6,546,'4691 T_01'),
(7,546,'4579 T_01'),
(8,757,'4688 T_01'),
(9,757,'4689 T_01'),
(10,757,'4691 T_01'),
(11,757,'4407 T_01'),
(12,855,'4410 T_01'),
(13,1249,'4583 A_01'),
(14,1324,'4689 T_01'),
(15,1324,'4690 T_01'),
(16,1411,'4689 T_01'),
(17,1411,'4690 T_01'),
(18,1411,'4478 A_01'),
(19,1411,'4411 T_01'),
(20,1411,'4692 T_01'),
(21,1411,'4406 T_01'),
(22,2115,'4410 T_01'),
(23,2115,'4414 T_01'),
(24,2115,'4422 T_01'),
(25,2325,'3422 T_01') ,
(26,2325,'4522 T_01') ,
(27,2330,'4462 T_01')   ) tbl (Id,Drv_uniqId,Trk_uniqId) 

我已经删除了示例预期输出,因为任何Drv_uniqId 进入哪个组都无关紧要,只要它们不存在于多个组中 - 任何解决方案都不必仅匹配此输出规则。 最少 5 个,最多 10 个

【问题讨论】:

  • 请提供预期输出
  • 对不起,我不明白逻辑......
  • @Shnugo 我希望能够根据 Drv_uniqId 对数据进行分组或拆分。 Drv_uniqId 不能存在于多个组中
  • @Cool_Br33ze,我已经可以在问题中找到了。但请用普通语言解释原因,例如第 8 行在第 2 组中,或者为什么第 3 组仅包含 1411,但第 4 组有几个 Drv_uniqId 值。这对你来说可能很清楚,但我看不到任何规则......
  • 对不起,我也无法理解逻辑。为什么记录 1-7 在同一组中,为什么 8-15 在不同的组中?

标签: tsql sql-server-2008-r2 grouping


【解决方案1】:

如果唯一的规则是您不能在多个组中拥有相同的Drv_uniqId 值,则可以使用按Drv_uniqId 排序的DENSE_RANK 来获取组:

SELECT  *, 
        DENSE_RANK() OVER(ORDER BY Drv_uniqId) rnk
FROM (VALUES
(1,530,'4392 T_01'),
(2,540,'4209 H_01'),
(3,540,'4551 T_01'),
(4,543,'4407 T_01'),
(5,543,'4691 T_01'),
(6,546,'4691 T_01'),
(7,546,'4579 T_01'),
(8,757,'4688 T_01'),
(9,757,'4689 T_01'),
(10,757,'4691 T_01'),
(11,757,'4407 T_01'),
(12,855,'4410 T_01'),
(13,1249,'4583 A_01'),
(14,1324,'4689 T_01'),
(15,1324,'4690 T_01'),
(16,1411,'4689 T_01'),
(17,1411,'4690 T_01'),
(18,1411,'4478 A_01'),
(19,1411,'4411 T_01'),
(20,1411,'4692 T_01'),
(21,1411,'4406 T_01'),
(22,2115,'4410 T_01'),
(23,2115,'4414 T_01'),
(24,2115,'4422 T_01'),
(25,2325,'3422 T_01') ,
(26,2325,'4522 T_01') ,
(27,2330,'4462 T_01')   ) tbl (Id,Drv_uniqId,Trk_uniqId) 
ORDER BY Id

See a live demo on rextester.

【讨论】:

  • 感谢您的回答,但我需要澄清我的问题。 DENSE_RANK 显示的每个组中不需要只有一个 Drv_uniqId
  • @Cool_Br33ze 但没有规则反对它,对吗?像这样编写(并让 sql server 执行)更容易,然后开始计算跨越多个 Drv_uniqId... 的组
【解决方案2】:

我的尝试涉及 WHILE LOOP 并计算 Running Total 如果有人可以提供更好的选择,那将不胜感激

DECLARE @tbl_table TABLE (Id INT IDENTITY(1,1), PartitionId INT, Total_Drv_uniqId INT NULL, Drv_uniqId INT, Trk_uniqId NVARCHAR(50), GrpSplit INT NULL );

;WITH cteX
AS(
    SELECT
          tbl.Id
        , tbl.Drv_uniqId
        , tbl.Trk_uniqId
    FROM (VALUES
        (1,530,'4392 T_01'),
        (2,540,'4209 H_01'),
        (3,540,'4551 T_01'),
        (4,543,'4407 T_01'),
        (5,543,'4691 T_01'),
        (6,546,'4691 T_01'),
        (7,546,'4579 T_01'),
        (8,757,'4688 T_01'),
        (9,757,'4689 T_01'),
        (10,757,'4691 T_01'),
        (11,757,'4407 T_01'),
        (12,855,'4410 T_01'),
        (13,1249,'4583 A_01'),
        (14,1324,'4689 T_01'),
        (15,1324,'4690 T_01'),
        (16,1411,'4689 T_01'),
        (17,1411,'4690 T_01'),
        (18,1411,'4478 A_01'),
        (19,1411,'4411 T_01'),
        (20,1411,'4692 T_01'),
        (21,1411,'4406 T_01'),
        (22,2115,'4410 T_01'),
        (23,2115,'4414 T_01'),
        (24,2115,'4422 T_01'),
        (25,2325,'3422 T_01') ,
        (26,2325,'4522 T_01') ,
        (27,2330,'4462 T_01')   ) tbl (Id,Drv_uniqId,Trk_uniqId) 
)
INSERT INTO @tbl_table
(PartitionId, Total_Drv_uniqId, Drv_uniqId, Trk_uniqId)
SELECT 
      RN = ROW_NUMBER()OVER(PARTITION BY X.Drv_uniqId ORDER BY X.Drv_uniqId)
    , COUNT(*)OVER(PARTITION BY X.Drv_uniqId)
    , X.Drv_uniqId
    , X.Trk_uniqId
FROM cteX X;
--GROUP BY X.Drv_uniqId

--Set Total_Drv_uniqId to 0 for duplicate rows so that Running total below is accurate
UPDATE @tbl_table SET Total_Drv_uniqId = 0 WHERE PartitionId > 1;

DECLARE @GrpSplit INT = 1, @maxLoop INT =1, @Rows INT;
SET @maxLoop = (SELECT MAX(V.Id) FROM @tbl_table V);

--Loop though to set GrpSplit using Running Total of [Total_Drv_uniqId]
WHILE @GrpSplit <= @maxLoop 
BEGIN

    UPDATE N
    SET N.GrpSplit = @GrpSplit
    FROM @tbl_table N
    INNER JOIN
    (
        SELECT ID
            , T1.Total_Drv_uniqId
            ,RunningTotal = (   SELECT SUM(T2.Total_Drv_uniqId)
                                FROM @tbl_table T2
                                WHERE T2.ID <= T1.ID
                            ) 
        FROM @tbl_table T1
        WHERE ( SELECT SUM(T2.Total_Drv_uniqId)
                FROM @tbl_table T2
                WHERE T2.ID <= T1.ID
                AND T2.GrpSplit IS NULL
             ) < 10
        AND T1.GrpSplit IS NULL
    ) X ON X.Id = N.Id;
    SET @Rows = @@ROWCOUNT ;

    IF @Rows < 1 BREAK ; --Break when no more rows to update 

    SET @GrpSplit += 1 ;

END;

SELECT T.Id, T.Drv_uniqId
     , T.Trk_uniqId
     , T.GrpSplit FROM @tbl_table T;

输出

Id  Drv_uniqId  Trk_uniqId  GrpSplit
1   530         4392 T_01   1
2   540         4551 T_01   1
3   540         4209 H_01   1
4   543         4691 T_01   1
5   543         4407 T_01   1
6   546         4691 T_01   1
7   546         4579 T_01   1
8   757         4689 T_01   2
9   757         4691 T_01   2
10  757         4407 T_01   2
11  757         4688 T_01   2
12  855         4410 T_01   2
13  1249        4583 A_01   2
14  1324        4689 T_01   2
15  1324        4690 T_01   2
16  1411        4690 T_01   3
17  1411        4478 A_01   3
18  1411        4411 T_01   3
19  1411        4692 T_01   3
20  1411        4406 T_01   3
21  1411        4689 T_01   3
22  2115        4410 T_01   3
23  2115        4414 T_01   3
24  2115        4422 T_01   3
25  2325        4522 T_01   4
26  2325        3422 T_01   4
27  2330        4462 T_01   4

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多