Rav*_*avi 3 performance sql-server-2008 sql-server t-sql query-performance
假设我有三个表或四个表,我想检查存在的值,但我不希望它们中的任何一个为空。如果它们为空,我将每行发送一封电子邮件通知。解决这个问题的最佳方法是什么?我应该单独使用 IF 语句创建存储过程吗?
我这样说是因为所有这些表都没有任何限制,它们只是从 Excel 表中提取数据。因此,即使列名不同,使表类型变量和联合或内部连接也不会返回任何内容,但它们存储的信息是相同类型的信息。因此,例如,如果在一个表中存在一个名为“DueDate”的列,在另一个表中,这种相同类型的信息称为“PaymentDate”。我将如何对所有这些表执行这样的检查?
更新:这是我现在想到的:假设两个表是 A 和 B,然后
DECLARE @messageBody NVARCHAR(MAX)
DECLARE @iterator int
DECLARE @Rowcount int
DECLARE @varTableA TABLE(tablecounter int IDENTITY(1,1), DueDate date, Account NVARCHAR(20), Retailer NVARCHAR(20), Interest float)
INSERT INTO @varTableA (DueDate, Account, Retailer, Interest)
SELECT DueDate, Account, Retailer, Interest
FROM TableA
WHERE DueDate IS NULL OR Account IS NULL OR Retailer IS NULL OR Interest IS NULL
SET @Rowcount = @@ROWCOUNT
SET @iterator = 1
WHILE(@iterator <= @Rowcount)
BEGIN
SET @messageBody = (SELECT 'No values in following columns' + 'Duedate: ' + ISNULL(Duedate, 'No value') + CHAR(10) + CHAR(13)
+ 'Account: ' + ISNULL(Account, 'No value') + CHAR(10) + CHAR(13)
+ 'Retailer: ' + ISNULL(Retailer, 'No Value') + CHAR(10) + CHAR(13)
+ 'Interest: ' + ISNULL(Interest, 'No Value') + CHAR(10) + CHAR(13)
FROM @varTableA
WHERE @tablecounter = @iterator)
EXEC msdb.dbo.sp_send_dbmail @profilename = [name], @recipients = [reclist], @subject = [sub], @body = @messageBody
SET @iterator = @iterator + 1
END
Run Code Online (Sandbox Code Playgroud)
并在 TableB 和 Table C 的相同或单独的存储过程中重复这一点。有没有更好的方法来做到这一点,或者你认为我的做法正确吗?
对于问题的第 1 部分,我在一个空数据库中创建了这三个表:
CREATE TABLE dbo.table1(a INT, b INT);
CREATE TABLE dbo.table2(a INT, b INT);
CREATE TABLE dbo.table3(a INT, b INT);
INSERT dbo.table1(a,b) VALUES(1,1),(1,2),(1,NULL);
INSERT dbo.table2(a,b) VALUES(1,1),(NULL,NULL),(1,NULL);
INSERT dbo.table3(a,b) VALUES(1,1),(1,2),(1,2);
Run Code Online (Sandbox Code Playgroud)
然后我写了这段代码来提取各种NULL
信息:
CREATE TABLE #x
(
t NVARCHAR(512), -- table name
nullrows INT NOT NULL DEFAULT 0, -- number of rows with at least one NULL
nullvalues INT NOT NULL DEFAULT 0, -- total NULL values in table
nulldist NVARCHAR(MAX) NOT NULL DEFAULT N'' -- how many NULLs in each column
);
INSERT #x(t) VALUES(N'dbo.table1'),(N'dbo.table2'),(N'dbo.table3');
Run Code Online (Sandbox Code Playgroud)
现在一些从元数据派生的动态 SQL 乐趣:
DECLARE @sql NVARCHAR(MAX) = N'';
SELECT @sql = @sql + N'
UPDATE #x SET nullrows = nullrows
+ (SELECT COUNT(*) FROM ' + t.t
+ N' WHERE (' + STUFF((SELECT N' OR '
+ QUOTENAME(c.name) + N' IS NULL'
FROM sys.columns AS c
WHERE OBJECT_ID(t.t) = c.[object_id]
FOR XML PATH, TYPE).value(N'.[1]',N'nvarchar(max)'),
1, 4, N'') + N')) WHERE t = N''' + t.t + N''';'
FROM #x AS t;
EXEC sys.sp_executesql @sql;
SET @sql = N'';
SELECT @sql = @sql + N'
IF EXISTS (SELECT 1 FROM ' + t + N' WHERE '
+ QUOTENAME(c.name) + N' IS NULL)
UPDATE #x SET nullvalues = nullvalues
+ (SELECT COUNT(*) FROM ' + t + N' WHERE '
+ QUOTENAME(c.name) + N' IS NULL),
nulldistribution = nulldistribution + '''
+ c.name + N':'' + RTRIM((SELECT COUNT(*) FROM '
+ t + N' WHERE ' + QUOTENAME(c.name) + N' IS NULL))
+ N'','' WHERE t = N''' + t + N''';'
FROM #x AS t
INNER JOIN sys.columns AS c
ON OBJECT_ID(t.t) = c.[object_id];
EXEC sys.sp_executesql @sql;
SELECT * FROM #x;
Run Code Online (Sandbox Code Playgroud)
结果:
t nullrows nullvalues nulldistribution
dbo.table1 1 1 b:1,
dbo.table2 2 3 a:1,b:2,
dbo.table3 0 0
Run Code Online (Sandbox Code Playgroud)
我将把它作为练习留给读者如何根据这些结果发送电子邮件——这似乎并不是其中最难的部分。
对于您问题的第 2 部分,正如我在评论中所说:
除了检查它们是否共享相同的数据类型之外,没有任何代码可以告诉您 DueDate 和 PaymentDate 包含相同类型的信息。这就是源代码控制和文档的用途。
我认为这是一个不同且无法回答的问题。
归档时间: |
|
查看次数: |
1469 次 |
最近记录: |