基于权重字段扩展数据集

sri*_*amn 5 sql-server sql-server-2008-r2

我有一个表格,其中包含未展开形式的记录。每条记录都有一个相关的整数权重,它基本上告诉我们应该复制多少次记录才能获得真实的人口。

说,我的表中有 3 条记录。sampnid 是唯一记录,weight是频率权重。未扩展的数据集如下所示:

sampn   weight  attrib1 attrib2 attrib3
    1       2       23      32      65
    2       1       32      56      75
    3       3       54      25      87
Run Code Online (Sandbox Code Playgroud)

展开后,数据集将如下所示(注意 - 我删除了该weight字段 - 但这不是必需的):

sampn   attrib1 attrib2 attrib3
    1       23      32      65
    1       23      32      65
    2       32      56      75
    3       54      25      87
    3       54      25      87
    3       54      25      87
Run Code Online (Sandbox Code Playgroud)

我曾尝试使用游标来做到这一点,但执行起来需要很长时间。有没有一种聪明的方法可以真正快速地做到这一点?任何预定义的 T-SQL 存储过程可以实现这一点?


全部更新,谢谢解答!真的很棒的学习体验!对我的数据集执行扩展操作。保罗的辅助数字表的执行时间最好。

Pau*_*ite 9

执行此任务的一种有效方法是使用辅助数字表。这只是一个从 1 到 n 的整数表,其中“n”可能是一百万左右。数字表可用于各种常规任务。

CREATE TABLE dbo.Demo
(
    SampleNumber    integer IDENTITY NOT NULL,
    SampleWeight    integer NOT NULL,
    Attribute1      integer NOT NULL,
    Attribute2      integer NOT NULL,
    Attribute3      integer NOT NULL,

    CONSTRAINT [PK dbo.Demo SampleNumber]
        PRIMARY KEY (SampleNumber),

    CONSTRAINT [CK dbo.Demo SampleWeight 1-50]
        CHECK (SampleWeight BETWEEN 1 AND 50)
);

INSERT INTO dbo.Demo
    (
    SampleWeight,
    Attribute1, 
    Attribute2, 
    Attribute3
    )
VALUES
    (2, 23, 32, 65),
    (1, 32, 56, 75),
    (3, 54, 25, 87);

SELECT
    D.SampleNumber,
    D.Attribute1,
    D.Attribute2,
    D.Attribute3
FROM dbo.Demo AS D
JOIN dbo.Numbers AS N
    ON N.n BETWEEN 1 AND D.SampleWeight;

DROP TABLE dbo.Demo;
Run Code Online (Sandbox Code Playgroud)

执行计划:

计划

输出:

???????????????????????????????????????????????????????
? SampleNumber ? Attribute1 ? Attribute2 ? Attribute3 ?
???????????????????????????????????????????????????????
?            1 ?         23 ?         32 ?         65 ?
?            1 ?         23 ?         32 ?         65 ?
?            2 ?         32 ?         56 ?         75 ?
?            3 ?         54 ?         25 ?         87 ?
?            3 ?         54 ?         25 ?         87 ?
?            3 ?         54 ?         25 ?         87 ?
???????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

SQLfiddle 在这里


Kin*_*hah 5

您可以使用CTE来做到这一点。

这是一个 sql 小提琴:http ://sqlfiddle.com/#!3/0b172/8

create table t(sampn int, weight   int, attrib1 int, attrib2 int, attrib3 int);

insert into t values    (1 ,      2 ,      23 ,     32   ,   65)
 insert into t values   (2  ,     1  ,     32  ,    56    ,  75)
  insert into t values  (3   ,    3   ,    54   ,   25     , 87)
Run Code Online (Sandbox Code Playgroud)

-- 使用 cte 的解决方案。

;WITH cte (
    sampn
    ,[weight]
    ,attrib1
    ,attrib2
    ,attrib3
    ,RepeatedTime
    )
AS (
    SELECT sampn
        ,[weight]
        ,attrib1
        ,attrib2
        ,attrib3
        ,1
    FROM t
    WHERE [weight] <> 0 -- this will take care if the weight is ZERO

    UNION ALL

    SELECT sampn
        ,[weight]
        ,attrib1
        ,attrib2
        ,attrib3
        ,RepeatedTime + 1
    FROM cte a
    WHERE a.[weight] > a.RepeatedTime
    )
SELECT sampn
    ,attrib1
    ,attrib2
    ,attrib3
FROM cte  
ORDER BY sampn
OPTION (MAXRECURSION 100) -- change this if you have more recursions
Run Code Online (Sandbox Code Playgroud)


Ada*_*nes 5

我同意 Paul 的观点,即数字表可能是您在可管理性和性能方面提出的最佳解决方案。话虽如此,您可以使用 XML 从不同的角度解决这个问题。

这个解决方案相当容易理解。少量行的性能应该没问题,但对于大量行,您将不得不进行测试。

更新:我已经在我的测试环境中添加了我正在使用的确切代码。

USE tempdb
GO

IF OBJECT_ID('tempdb.dbo.Demo') IS NOT NULL
BEGIN
    DROP TABLE dbo.Demo;
END
GO

CREATE TABLE dbo.Demo
(
    SampleNumber    integer IDENTITY NOT NULL,
    SampleWeight    integer NOT NULL,
    Attribute1      integer NOT NULL,
    Attribute2      integer NOT NULL,
    Attribute3      integer NOT NULL,

    CONSTRAINT [PK dbo.Demo SampleNumber]
        PRIMARY KEY (SampleNumber),

    CONSTRAINT [CK dbo.Demo SampleWeight 1-50]
        CHECK (SampleWeight BETWEEN 1 AND 50)
);

INSERT INTO dbo.Demo
    (
    SampleWeight,
    Attribute1, 
    Attribute2, 
    Attribute3
    )
VALUES
    (2, 23, 32, 65),
    (1, 32, 56, 75),
    (3, 54, 25, 87);
GO

SELECT 
    y.SampleNumber,
    Att.vals.value('@Attribute1','int'),
    Att.vals.value('@Attribute2','int'),
    Att.vals.value('@Attribute3','int')
FROM(
    SELECT 
        SampleNumber,
        Attribute=(SELECT CAST(REPLICATE(CAST(Attribute.Data AS VARCHAR(MAX)),SampleWeight) AS XML))
    FROM dbo.Demo
    CROSS APPLY(   
        SELECT 
            [@Attribute1] = Attribute1,
            [@Attribute2] = Attribute2,
            [@Attribute3] = Attribute3
        FOR XML PATH('data'),ROOT('root'), TYPE
    ) AS Attribute (Data)
) AS y
CROSS APPLY y.Attribute.nodes('/root/data') as Att(vals)
Run Code Online (Sandbox Code Playgroud)