动态 SQL Server 查询循环遍历架构查找主键重复
Posted
技术标签:
【中文标题】动态 SQL Server 查询循环遍历架构查找主键重复【英文标题】:Dynamic SQL Server Query loop through schema find primary key duplicate 【发布时间】:2022-01-17 07:03:54 【问题描述】:编辑: create table 语句似乎有些混乱。这些只是为了演示哪些表*可能会进入我们的突触实例,而不是作为将运行的实际代码。问题的重要部分包含在后半部分。
我正在尝试创建一个存储过程,该过程循环遍历提供的架构中的每个表并输出每个表的重复主键行的计数。假设数据是从其他地方提供的,并且没有强制执行主键。例如,我可能在堆栈模式中有三个表:
CREATE TABLE stack.table1(
id int,
name NVARCHAR(MAX),
color NVARCHAR(20)
PRIMARY KEY (id))
INSERT INTO stack.table1 VALUES(1,'item1','yellow')
(2,'item2','blue')
(2,'item2','blue')
CREATE TABLE stack.table2(
id int,
name NVARCHAR(MAX),
size NVARCHAR(1)
PRIMARY KEY (id,size))
INSERT INTO stack.table2 VALUES(1,'item1','L')
(2,'item2','M')
(3,'item2','S')
CREATE TABLE stack.table3(
id int,
name NVARCHAR(MAX),
weight NVARCHAR(20)
PRIMARY KEY (id))
INSERT INTO stack.table1 VALUES(1,'item1','200lb')
(2,'item2','150lb')
(3,'item2','125lb')
我想为存储过程提供一个变量以指示架构(在本例中为“堆栈”),并让该过程吐出一个表,其中包含架构中表的名称和重复主键行的计数.因此,在本例中,名为“loopcheck”的存储过程如下所示:
查询:
EXEC loopcheck @schema = 'stack'
输出:
table | duplicate_count |
---|---|
table1 | 1 |
table2 | 0 |
table3 | 0 |
我使用的是 Azure Synapse 实例,因此有几个函数不可用(例如 FOR XML PATH 等。)由于每个表可能有一个单列主键或一个复合主键,我需要加入系统提供了表格来获取主键信息。我的总体思路是这样的:
CREATE procedure loopcheck @schema= NVARCHAR(MAX)
AS
BEGIN
create table #primarykey(
SCHEMA_NAME nvarchar(400),
TABLE_NAME nvarchar(500),
COLUMN_NAME nvarchar(500)
)
insert into #primarykey
select l.TABLE_SCHEMA,
l.TABLE_NAME,
l.COLUMN_NAME
from INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE l
inner join INFORMATION_SCHEMA.TABLE_CONSTRAINTS t on l.constraint_Name = t.CONSTRAINT_NAME
where
l.table_schema = @schema
CREATE TABLE #groupBy2(
TABLE_NAME nvarchar(50),
groupby nvarchar(200)
)
INSERT INTO #groupBy2
SELECT TABLE_NAME, STRING_AGG(CONVERT(NVARCHAR(max), COLUMN_NAME), ',') as groupby
FROM #primarykey
GROUP BY TABLE_NAME
DECLARE @currentTable NVARCHAR(MAX)=''
DECLARE @currentGroup NVARCHAR(MAX)=''
create table #work4(
TABLE_NAME nvarchar(400),
COUNT int)
DECLARE @final NVARCHAR(MAX)=
'INSERT INTO #work4
SELECT '+@currentTable+', COUNT(*) FROM '+@currentTable+'GROUP BY'+@currentGroup
WHILE (SELECT COUNT(*) FROM #groupby2)>0
BEGIN
SET @currentTable =(SELECT TOP 1 TABLE_NAME FROM #groupby2 ORDER BY TABLE_NAME)
SET @currentGroup =(SELECT TOP 1 groupby FROM #groupby2 ORDER BY TABLE_NAME)
exec @final
DELETE #groupby2 where TABLE_NAME =@currentTable
END
END
这段代码给了我一个错误:
“SELECT”附近的语法不正确
但没有给我错误所在的实际行。
【问题讨论】:
尝试执行@final 时是否发生错误?还是在静态SQL?要调试您执行的动态 SQL 更改以打印和测试生成的 SQL。 这里没有加起来。您不能有重复的主键值。这就是主键的意义所在。而且“没有强制执行主键”完全没有意义。也许您所指的实际上不是主键?我完全无法理解你的问题。 您能否展示一个您知道有重复表的示例(CREATE TABLE 语句)?正如@SeanLange 所提到的,也许您实际上没有定义主键,或者您没有引用主键本身,而是引用了其他一些没有相应约束的列。除非您以某种方式禁用了约束,否则 table1 的插入应该会失败,这将是一件奇怪的事情。 查看以下小提琴,使用您的数据库(SQL Server):https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=1f40cdb8367834a6d816e79d5173de62
我同意@SeanLange - 你的问题没有意义。实际上,您的脚本不会为 table stack.table1 插入“重复”行,因为它确实在 ID 列上定义了 PK。我的猜测是,您应该使用使该行唯一的所有列定义一个复合键(至少是唯一约束)。如果是这种情况 - 动态创建任何代码是不可能的,因为您不知道需要哪些列来唯一标识每一行。
【参考方案1】:
您的主要问题是语法错误:参数声明不应在名称和类型名称之间包含 =
,并且动态 SQL 中缺少空格。
还有
架构名称(或任何对象)最多可以是nvarchar(128)
,您可以使用别名sysname
你不需要做任何循环或使用临时表,你可以构建一个大的动态语句来执行
CREATE procedure loopcheck
@schema sysname
AS
DECLARE @sql nvarchar(max) = (
SELECT STRING_AGG(CAST('
SELECT
TableName = ' + QUOTENAME(t.name, '''') + ',
IndexName = ' + QUOTENAME(i.name, '''') + ',
Duplicates = COUNT(*)
FROM (
SELECT 1 n
FROM ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name) + ' t
GROUP BY ' + cols.agg + '
HAVING COUNT(*) > 1
) t
'
AS nvarchar(max)), 'UNION ALL')
FROM sys.tables t
JOIN sys.schemas s ON s.schema_id = t.schema_id
AND s.name = @schema
JOIN sys.indexes i ON i.object_id = t.object_id
AND i.is_unique = 1
CROSS APPLY (
SELECT STRING_AGG('t.' + QUOTENAME(c.name), ', ')
FROM sys.index_columns ic
JOIN sys.columns c ON c.column_id = ic.column_id AND c.object_id = t.object_id
WHERE ic.index_id = i.index_id
AND ic.object_id = i.object_id
AND ic.is_included_column = 0
) cols(agg)
);
PRINT @sql; -- for testing
EXEC sp_executesql @sql;
db<>fiddle
我觉得在单个表上有多个唯一索引/约束的情况下,使用GROUPING SETS
可能会更有效一些,但我将把它留给你。
【讨论】:
这也有几个语法错误。您是否运行过此查询? 抱歉复制/粘贴混淆,现在应该修复以上是关于动态 SQL Server 查询循环遍历架构查找主键重复的主要内容,如果未能解决你的问题,请参考以下文章
Oracle动态游标实现动态SQL循环遍历,和静态游标的比较。