检查多个表的所有列中的空值的最有效方法是什么?

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 的相同或单独的存储过程中重复这一点。有没有更好的方法来做到这一点,或者你认为我的做法正确吗?

Aar*_*and 5

对于问题的第 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 包含相同类型的信息。这就是源代码控制和文档的用途。

我认为这是一个不同且无法回答的问题。