sql - 遍历表和字段列表并将它们混合

标签 sql sql-server algorithm loops sql-server-2008-r2

我正在寻找一种有效的方法来覆盖给定的需要混合的表和字段列表。

我想这应该成为一个函数或存储过程。

输入应该是某种表名列表,对于每个表,应该有另一个列表,其中包含唯一索引列、一个键列,然后是所有其他需要混合的列。

算法和给定的代码解释如下:

首先,混合我的意思是将所有值保留在每一列中,但以不同的顺序在行之间重新分配它们。

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 列的表:Index、Id、Name、Address 该算法对 ID 和名称重新排序,向每一行添加一个数字。 由于行数相同,我可以按行号连接两个重新排序的列,然后更新原始表 - 将一列 (ColumnToMix) 更改为重新分配的值。 假设原始表名为“People”,如下所示:

Index Id   Name   Address 
1     52   Jill   New-York
2     57   John   Chicago
5     63   Bill   Alabama

变量将是 @tablename = 人,@keyColumn = 索引,@ColumnForBase = Id,@ColumnToMix = 姓名

运行上面代码的结果是

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 表示代表“自然”顺序的列 - 就像标识列或创建日期列。请注意,表中的记录没有自然顺序,因为表根据定义是未排序的。

但是为了参数化表名和列名,你需要在存储过程中使用动态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

我建议不要在一次执行中混合多个列,因为它们将以相同的随机顺序混合 - 但是您可以创建另一个过程来获取您想要的参数(表名,它的主键和列表它是要混合的列)并分别为每列运行此过程。

You can see a live demo on rextester (基于您提供的样本数据)。

关于sql - 遍历表和字段列表并将它们混合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55086405/

相关文章:

sql - 如何处理原始可空类型的 Spark UDF 输入/输出

SQLite:防止重复行

sql - 是否可以在 postgresql 中为每个主键创建索引?

sql-server - 使用 Windows 身份验证从 Spring Boot 应用程序连接到 MSSQL

sql-server - 我可以与 ADO 一起使用的最简单的数据库类型是什么?

ruby - Ruby 的三和算法

algorithm - 求 0 和 1 形式的倍数

c# - 变量名 '@KorisnickoIme' 已经声明。变量名称在查询批处理或存储过程中必须是唯一的

sql - 对数据进行分组并维护计算字段

algorithm - 如何比较两个形状?