遍历表和字段列表并将它们混合
loop over a list of tables and field and mix them
我正在寻找一种有效的方法来覆盖给定的 table 列表和需要混合的字段。
我想这应该成为一个函数或存储过程。
输入应该是某种 table 名称的列表,对于每个 table 应该有另一个列表,其中包含唯一索引列、一个键列,然后是所有其他列需要混合。
算法和给出的代码解释如下:
首先,混合我的意思是将所有值保留在每一列中,但以不同的顺序在行之间重新分配它们。
SQL语法:
declare @tablename varchar, @keyColumn varchar, @ColumnForBase ,@ColumnToMix
update [@tablename]
set [@tablename].[@ColumnToMix]=c.[@ColumnToMix],[@tablename].[@ColumnForBase]=c.[@ColumnForBase]
from [@tablename] left join
(
SELECT a.[@ColumnToMix] as [@ColumnToMix] ,b.[@ColumnForBase] as [@ColumnForBase],b.[@keyColumn] as [@keyColumn]
FROM
(SELECT row_number() OVER (ORDER BY [@ColumnToMix]) num, [@ColumnToMix]
FROM [@tablename]) as a
left join
(SELECT row_number() OVER (ORDER BY [@ColumnForBase]) num, [@keyColumn],[@ColumnForBase]
FROM [@tablename] ) as b
ON a.num=b.num
)as c ON c.[@keyColumn]=[@tablename].[@keyColumn]
解释和例子:
假设我有一个包含 4 列的 table:索引、ID、名称、地址
该算法对 ID 和名称重新排序,向每一行添加一个数字。
由于行数相同,我可以按行号连接两个重新排序的列,然后更新原始 table - 将一列 (ColumnToMix) 更改为重新分配的值。
假设原来的 table 被称为 "People" 并且看起来像这样:
Index Id Name Address
1 52 Jill New-York
2 57 John Chicago
5 63 Bill Alabama
变量是
@tablename = 人,@keyColumn = 索引,@ColumnForBase = Id,@ColumnToMix = Name
上面代码运行的结果是
Index Id Name Address
1 52 Bill New-York
2 57 Jill Chicago
5 63 John Alabama
名字现在混在一起了。
为了混合多于一列,代码需要能够遍历所有必要的字段。
有什么想法吗?
好吧,对于一个硬编码专栏来说,这是一项相当简单的任务:
UPDATE T0
SET Name = T1.Name
FROM
(
SELECT Name, ROW_NUMBER() OVER(ORDER BY OriginalOrderColumn) As RN
FROM Table
) AS T0
JOIN
(
SELECT Name, ROW_NUMBER() OVER(ORDER BY NEWID()) As RN
FROM Table
) AS T1
ON T0.RN = T1.RN
*OriginalOrderColumn 表示代表 "natural" 订单的列 - 类似于标识列或创建日期列。请注意 table 中的记录没有自然顺序,因为 table 根据定义未排序。
但是为了参数化 table 名称和列名称,您需要在存储过程中使用动态 SQL:
CREATE PROCEDURE MixValuesInAColumn
(
@TableName sysname,
@ColumnToMix sysname,
@OriginalOrderBy sysname
)
AS
-- White-listing table and column names
IF EXISTS
(
SELECT 1
FROM Information_Schema.Columns
WHERE TABLE_NAME = @TableName
AND COLUMN_NAME = @ColumnToMix
) AND EXISTS
(
SELECT 1
FROM Information_Schema.Columns
WHERE TABLE_NAME = @TableName
AND COLUMN_NAME = @OriginalOrderBy
) BEGIN
DECLARE @Sql nvarchar(max) =
'UPDATE T0 SET '+ QUOTENAME(@ColumnToMix) +' = T1.'+ QUOTENAME(@ColumnToMix) +' '+
'FROM (
SELECT '+ @ColumnToMix +', ROW_NUMBER() OVER(ORDER BY '+ QUOTENAME(@OriginalOrderBy) +') As [Original Order]
FROM '+ QUOTENAME(@TableName) + '
) As T0
JOIN
(
SELECT '+ QUOTENAME(@ColumnToMix) +', ROW_NUMBER() OVER(ORDER BY NEWID()) As [Random Order]
FROM '+ QUOTENAME(@TableName) + '
) AS T1 ON T0.[Original Order] = T1.[Random Order]'
EXEC(@SQL)
END
我建议不要在一次执行中混合多个列,因为它们将以相同的随机顺序混合 - 但是您可以创建另一个过程来获取您想要的参数(table 名称,它是主键及其要混合的列的列表)和 运行 此过程分别针对每一列。
You can see a live demo on rextester(基于您提供的示例数据)。
我正在寻找一种有效的方法来覆盖给定的 table 列表和需要混合的字段。
我想这应该成为一个函数或存储过程。
输入应该是某种 table 名称的列表,对于每个 table 应该有另一个列表,其中包含唯一索引列、一个键列,然后是所有其他列需要混合。
算法和给出的代码解释如下:
首先,混合我的意思是将所有值保留在每一列中,但以不同的顺序在行之间重新分配它们。
SQL语法:
declare @tablename varchar, @keyColumn varchar, @ColumnForBase ,@ColumnToMix
update [@tablename]
set [@tablename].[@ColumnToMix]=c.[@ColumnToMix],[@tablename].[@ColumnForBase]=c.[@ColumnForBase]
from [@tablename] left join
(
SELECT a.[@ColumnToMix] as [@ColumnToMix] ,b.[@ColumnForBase] as [@ColumnForBase],b.[@keyColumn] as [@keyColumn]
FROM
(SELECT row_number() OVER (ORDER BY [@ColumnToMix]) num, [@ColumnToMix]
FROM [@tablename]) as a
left join
(SELECT row_number() OVER (ORDER BY [@ColumnForBase]) num, [@keyColumn],[@ColumnForBase]
FROM [@tablename] ) as b
ON a.num=b.num
)as c ON c.[@keyColumn]=[@tablename].[@keyColumn]
解释和例子:
假设我有一个包含 4 列的 table:索引、ID、名称、地址 该算法对 ID 和名称重新排序,向每一行添加一个数字。 由于行数相同,我可以按行号连接两个重新排序的列,然后更新原始 table - 将一列 (ColumnToMix) 更改为重新分配的值。 假设原来的 table 被称为 "People" 并且看起来像这样:
Index Id Name Address
1 52 Jill New-York
2 57 John Chicago
5 63 Bill Alabama
变量是 @tablename = 人,@keyColumn = 索引,@ColumnForBase = Id,@ColumnToMix = Name
上面代码运行的结果是
Index Id Name Address
1 52 Bill New-York
2 57 Jill Chicago
5 63 John Alabama
名字现在混在一起了。
为了混合多于一列,代码需要能够遍历所有必要的字段。
有什么想法吗?
好吧,对于一个硬编码专栏来说,这是一项相当简单的任务:
UPDATE T0
SET Name = T1.Name
FROM
(
SELECT Name, ROW_NUMBER() OVER(ORDER BY OriginalOrderColumn) As RN
FROM Table
) AS T0
JOIN
(
SELECT Name, ROW_NUMBER() OVER(ORDER BY NEWID()) As RN
FROM Table
) AS T1
ON T0.RN = T1.RN
*OriginalOrderColumn 表示代表 "natural" 订单的列 - 类似于标识列或创建日期列。请注意 table 中的记录没有自然顺序,因为 table 根据定义未排序。
但是为了参数化 table 名称和列名称,您需要在存储过程中使用动态 SQL:
CREATE PROCEDURE MixValuesInAColumn
(
@TableName sysname,
@ColumnToMix sysname,
@OriginalOrderBy sysname
)
AS
-- White-listing table and column names
IF EXISTS
(
SELECT 1
FROM Information_Schema.Columns
WHERE TABLE_NAME = @TableName
AND COLUMN_NAME = @ColumnToMix
) AND EXISTS
(
SELECT 1
FROM Information_Schema.Columns
WHERE TABLE_NAME = @TableName
AND COLUMN_NAME = @OriginalOrderBy
) BEGIN
DECLARE @Sql nvarchar(max) =
'UPDATE T0 SET '+ QUOTENAME(@ColumnToMix) +' = T1.'+ QUOTENAME(@ColumnToMix) +' '+
'FROM (
SELECT '+ @ColumnToMix +', ROW_NUMBER() OVER(ORDER BY '+ QUOTENAME(@OriginalOrderBy) +') As [Original Order]
FROM '+ QUOTENAME(@TableName) + '
) As T0
JOIN
(
SELECT '+ QUOTENAME(@ColumnToMix) +', ROW_NUMBER() OVER(ORDER BY NEWID()) As [Random Order]
FROM '+ QUOTENAME(@TableName) + '
) AS T1 ON T0.[Original Order] = T1.[Random Order]'
EXEC(@SQL)
END
我建议不要在一次执行中混合多个列,因为它们将以相同的随机顺序混合 - 但是您可以创建另一个过程来获取您想要的参数(table 名称,它是主键及其要混合的列的列表)和 运行 此过程分别针对每一列。
You can see a live demo on rextester(基于您提供的示例数据)。