sri*_*amn 5 sql-server sql-server-2008-r2
我有一个表格,其中包含未展开形式的记录。每条记录都有一个相关的整数权重,它基本上告诉我们应该复制多少次记录才能获得真实的人口。
说,我的表中有 3 条记录。sampn
id 是唯一记录,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 存储过程可以实现这一点?
全部更新,谢谢解答!真的很棒的学习体验!对我的数据集执行扩展操作。保罗的辅助数字表的执行时间最好。
执行此任务的一种有效方法是使用辅助数字表。这只是一个从 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)
您可以使用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)
我同意 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)
归档时间: |
|
查看次数: |
237 次 |
最近记录: |