根据条件为行分区分配一个数字

时间:2018-10-18 09:23:07

标签: sql sql-server

给出下表

ID, FileSize, PrintGroup
1   100         1
2   300         1
3   500         1
4   600         1
5   700         1
6   100         1
7   200         1
8   300         1
9   200         1
10  200         1
11  300         1
12  400         1
13  100         1
14  300         1
15  200         2
16  300         2
17  400         2
18  100         2
19  300         2
20  200         2
21  300         2
22  400         2
23  100         2
24  300         2
25  200         2
26  300         2
27  400         2
28  100         2
29  300         2

我试图创建一个包含数字的列,该数字将附加到文件名中,以确保每个打印组的zip文件不超过特定大小。 例如: 在这种情况下,如果我的最大拉链尺寸为1000。 ID 1,2,3,6可能位于SplitAllocationNumber 1中,依此类推,因为其FileSize列的总和为<= 1000

我尝试过NTILE,但是不能保证每个组的FileSize的总和小于或等于最大值(在此示例中为1000) 这是我到目前为止尝试过的查询

DECLARE @maximumZipSize INT = 1000;

DECLARE @totalFileSize INT = (
        SELECT SUM(FileSize)
        FROM [PendingDocuments]
        );

DECLARE @ceiling DECIMAL(10,2) = @totalFileSize / CAST(@maximumZipSize AS DECIMAL(10,2));

DECLARE @totalGroups INT = (
        CASE CEILING(@ceiling)
            WHEN 0
                THEN 1
            ELSE CEILING(@ceiling)
            END
        );

SELECT 'Total Groups: ', @totalGroups
UNION
SELECT 'Total File Size: ', @totalFileSize
UNION
SELECT 'Max Zip Size: ', @maximumZipSize
UNION
SELECT 'Ceiling Result:', @ceiling

SELECT 
    p.ID,
    FileSize,
    p.PrintGroup,
    SplitAllocation.Number
FROM PendingDocuments p
INNER JOIN
(
    SELECT
        ID,
        NTILE(@totalGroups) OVER (PARTITION BY PrintGroup ORDER BY ID) AS Number
    FROM PendingDocuments
) AS SplitAllocation
ON p.ID = SplitAllocation.ID

如何确保每个组的FileSize之和为<= 1000?

2 个答案:

答案 0 :(得分:0)

不幸的是,这种类型的问题本质上是迭代的。稍有变化-您可以将垃圾箱完全填充到1000个,然后在两个垃圾箱之间的边界处拆分文件-并不是迭代的。

因此,我知道的唯一解决方案是使用递归CTE:

stop

您的问题提到将bin附加到文件名上。我没有在问题中看到文件名,我认为一旦分配了垃圾箱,您就可以处理所需的任何后续处理。

答案 1 :(得分:0)

只要有人想知道答案,我就结合使用CTE和递归CTE以获得预期的结果。

class People extends React.Component {
  constructor(props) {
    super(props);
    // assuming props.people is an array of objects containing name, gender, type, etc.
    const people = props.people;

    this.state = {
      Person: people,
      filteredPerson: people,
    };
  }

  setFilter = (gender) => {
    const uppercaseGender = gender.toUpperCase();
    const filteredPerson = this.state.Person.filter(e =>
      e.gender.toUpperCase().indexOf(uppercaseGender) >= 0
    );

    this.setState({ filteredPerson });
  }

  render() {
    return (
      <div>
        /* map over this.state.filteredPerson and display the data */
        <button onClick={() => setFilter('male')}>male</button>
        <button onClick={() => setFilter('female')}>female</button>
      </div>
    );
  }
}