0

在此处输入图像描述

我在下面有一个查询,它应该带回 NULL 记录数、列的 MinValue、MaxValue 和 AvgValue 的记录。但是,查询运行但不带回记录,只带回列标题,当它肯定应该带回时。你能更正我的代码以显示我哪里出错了吗?计算字段应仅适用于数字、浮点、小数和其他选定的数据类型,如下面的查询中所定义。

DECLARE @schemaName AS sysname;
    DECLARE @tableName AS sysname;
    DECLARE @columnName AS sysname;
    DECLARE @schema_id AS int;
    DECLARE @object_id AS int;
    DECLARE @column_id AS int;
    DECLARE @isNullable AS bit;
    DECLARE @lastSchema_id AS int;
    DECLARE @lastTable_id AS int;
    DECLARE @recordCount AS bigint;
    DECLARE @MinValue As int;
    DECLARE @MaxValue As int;
    DECLARE @AvgValue As int;
    DECLARE @nullCnt AS bigint;
    DECLARE @SQL as nvarchar(max);
    DECLARE @paramDefinition NVARCHAR(max);

    if exists(select name from tempdb..sysobjects where name LIKE'#Columns%')
    DROP TABLE #Columns;

    CREATE TABLE #Columns (
        schema_id int,
        object_id int,
        column_id int,
        schemaName sysname,
        tableName sysname,
        columnName sysname,
        recordCnt bigint,
        MinValue int,
        MaxValue int,
        AvgValue int,
        nullCnt bigint,
        nullPct numeric(38,35) );

    -- Set to the @lastSchema_id and @lastTable_id to NULL so that the first 
    --  loop through the cursor the record count is generated.
    SET @lastSchema_id = NULL;
    SET @lastTable_id = NULL;

    -- List of all the user schemas.tables.columns
    --  in the database
    DECLARE c_Cursor CURSOR FOR
    SELECT schemas.schema_id
         , all_objects.object_id
         , all_columns.column_id
         , schemas.name AS schemaName
         , all_objects.name AS tableName
         , all_columns.name AS columnName
         , all_columns.is_nullable
      FROM sys.schemas
     INNER JOIN sys.all_objects
        ON schemas.schema_id = all_objects.schema_id
       AND all_objects.type = 'U'
     INNER JOIN sys.all_columns
        ON all_objects.object_id = all_columns.object_id
         WHERE all_objects.type LIKE '%int%'
         OR all_objects.type LIKE '%float%' 
         OR all_objects.type LIKE '%decimal%'
         OR all_objects.type LIKE '%numeric%'
         OR all_objects.type LIKE '%real%'
         OR all_objects.type LIKE '%money%'
     ORDER BY schemas.schema_id
         , all_objects.object_id
         , all_columns.column_id;

    OPEN c_Cursor;

    FETCH NEXT FROM c_Cursor
     INTO @schema_id
        , @object_id
        , @column_id
        , @schemaName
        , @tableName
        , @columnName
        , @isNullable;

    -- Loop through the cursor
    WHILE @@FETCH_STATUS = 0
    BEGIN

        -- Get the record count for the table we are currently working on if this is
        --  the first time we are encountering the table.
        IF ( ( @schema_id <> @lastSchema_id ) OR ( @object_id <> @lastTable_id )
          OR ( @lastSchema_id IS NULL ) OR ( @lastTable_id IS NULL ) )
        BEGIN

            SET @SQL = N'SELECT @recordCount = COUNT(1) FROM ' + QUOTENAME(@schemaName) + N'.' + QUOTENAME(@tableName) + ';';
            SET @paramDefinition = N'@recordCount bigint OUTPUT';

            exec sp_executesql @SQL,
                               @paramDefinition,
                               @recordCount = @recordCount OUTPUT;

        END

        -- Get the min value for the table 

    IF ( ( @schema_id <> @lastSchema_id ) OR ( @object_id <> @lastTable_id )
          OR ( @lastSchema_id IS NULL ) OR ( @lastTable_id IS NULL ) )
        BEGIN

            SET @SQL = N'SELECT @MinValue = COUNT(1) FROM ' + QUOTENAME(@schemaName) + N'.' + QUOTENAME(@tableName) + ';';
            SET @paramDefinition = N'@MinValue int OUTPUT';

            exec sp_executesql @SQL,
                               @paramDefinition,
                               @MinValue = @MinValue OUTPUT;

        END

        --Get the max value for the table

        IF ( ( @schema_id <> @lastSchema_id ) OR ( @object_id <> @lastTable_id )
          OR ( @lastSchema_id IS NULL ) OR ( @lastTable_id IS NULL ) )
        BEGIN

            SET @SQL = N'SELECT @MaxValue = COUNT(1) FROM ' + QUOTENAME(@schemaName) + N'.' + QUOTENAME(@tableName) + ';';
            SET @paramDefinition = N'@MaxValue int OUTPUT';

            exec sp_executesql @SQL,
                               @paramDefinition,
                               @MaxValue = @MaxValue OUTPUT;

        END

        --Get the avg value for the table
    IF ( ( @schema_id <> @lastSchema_id ) OR ( @object_id <> @lastTable_id )
          OR ( @lastSchema_id IS NULL ) OR ( @lastTable_id IS NULL ) )
        BEGIN

            SET @SQL = N'SELECT @AvgValue = COUNT(1) FROM ' + QUOTENAME(@schemaName) + N'.' + QUOTENAME(@tableName) + ';';
            SET @paramDefinition = N'@AvgValue int OUTPUT';

            exec sp_executesql @SQL,
                               @paramDefinition,
                               @AvgValue = @AvgValue OUTPUT;

        END



        -- If the column is NOT NULL, there is no reason to do a count
        --  Set the nullCnt and nullPct to 0
        IF ( @isNullable = 0 )
        BEGIN


            INSERT INTO #Columns
                 ( [schema_id]
                 , [object_id]
                 , column_id
                 , schemaName
                 , tableName
                 , columnName
                 , recordCnt
                 , nullCnt
                 , nullPct )
            VALUES
                 ( @schema_id
                 , @object_id
                 , @column_id
                 , @schemaName
                 , @tableName
                 , @columnName
                 , @recordCount
                 , 0
                 , 0.0 );
        END
        -- If the column is NULL, count the number of NULL fields in the table.
        ELSE
        BEGIN

            SET @SQL = N'SELECT @nullCnt = COUNT(1) FROM ' + QUOTENAME(@schemaName) + N'.' + QUOTENAME(@tableName) + 
                       N' WHERE ' + QUOTENAME(@columnName) + N' IS NULL;';
            SET @paramDefinition = N'@nullCnt bigint OUTPUT';

            PRINT @SQL;

            exec sp_executesql @SQL,
                               @paramDefinition,
                               @nullCnt = @nullCnt OUTPUT;

            INSERT INTO #Columns
                 ( [schema_id]
                 , [object_id]
                 , column_id
                 , schemaName
                 , tableName
                 , columnName
                 , recordCnt
                 , nullCnt
                 , nullPct )
            VALUES
                 ( @schema_id
                 , @object_id
                 , @column_id
                 , @schemaName
                 , @tableName
                 , @columnName
                 , @recordCount
                 , @nullCnt
                 -- USE NULLIF in case there are no recods in the table
                 , ISNULL( @nullCnt * 1.0 / NULLIF( @recordCount, 0) * 100.0, 0 ) );

        END

        -- Set the @lastSchema_id and @lastTable_id so that on 
        --  the next loop, if it's the same table there is no 
        --  need to recount the columns for the table.
        SET @lastSchema_id = @schema_id;
        SET @lastTable_id = @object_id;

        FETCH NEXT FROM c_Cursor
         INTO @schema_id
            , @object_id
            , @column_id
            , @schemaName
            , @tableName
            , @columnName
            , @isNullable;

    END;

    CLOSE c_Cursor;
    DEALLOCATE c_Cursor;

    SELECT *
      FROM #Columns;
4

1 回答 1

1

问题是您用于游标的第一个查询:

   SELECT schemas.schema_id
         , all_objects.object_id
         , all_columns.column_id
         , schemas.name AS schemaName
         , all_objects.name AS tableName
         , all_columns.name AS columnName
         , all_columns.is_nullable
      FROM sys.schemas
     INNER JOIN sys.all_objects
        ON schemas.schema_id = all_objects.schema_id
       AND all_objects.type = 'U'
     INNER JOIN sys.all_columns
        ON all_objects.object_id = all_columns.object_id
         WHERE all_objects.type LIKE '%int%'
         OR all_objects.type LIKE '%float%' 
         OR all_objects.type LIKE '%decimal%'
         OR all_objects.type LIKE '%numeric%'
         OR all_objects.type LIKE '%real%'
         OR all_objects.type LIKE '%money%'
     ORDER BY schemas.schema_id
         , all_objects.object_id
         , all_columns.column_id;

如果你仔细检查,你会做一个INNER JOINonall_object.type = 'U'所以所有类型都必须是U,但是WHERE你在同一个 oclumn 上使用列类型做额外的过滤,因为你已经按 type 过滤,所以这总是错误的U

我认为您想按列数据类型进行过滤,您必须在其中正确执行附加连接和过滤,如下所示:

SELECT 
    schemas.schema_id
    , all_objects.object_id
    , all_columns.column_id
    , schemas.name AS schemaName
    , all_objects.name AS tableName
    , all_columns.name AS columnName
    , all_columns.is_nullable
FROM 
    sys.schemas
    INNER JOIN sys.all_objects
    ON schemas.schema_id = all_objects.schema_id
    AND all_objects.type = 'U'
    INNER JOIN sys.all_columns
    ON all_objects.object_id = all_columns.object_id

    INNER JOIN sys.types 
    ON all_columns.system_type_id = types.system_type_id
    AND all_columns.user_type_id = types.user_type_id

WHERE 
    types.name LIKE '%int%'
    OR types.name LIKE '%float%' 
    OR types.name LIKE '%decimal%'
    OR types.name LIKE '%numeric%'
    OR types.name LIKE '%real%'
    OR types.name LIKE '%money%'
ORDER BY 
    schemas.schema_id
    , all_objects.object_id
    , all_columns.column_id;

编辑:这是更正后的完整脚本。下面提到的错误。

DECLARE @schemaName AS sysname;
DECLARE @tableName AS sysname;
DECLARE @columnName AS sysname;
DECLARE @schema_id AS int;
DECLARE @object_id AS int;
DECLARE @column_id AS int;
DECLARE @isNullable AS bit;
DECLARE @lastSchema_id AS int;
DECLARE @lastTable_id AS int;
DECLARE @recordCount AS bigint;
DECLARE @MinValue As int;
DECLARE @MaxValue As int;
DECLARE @AvgValue As int;
DECLARE @nullCnt AS bigint;
DECLARE @SQL as nvarchar(max);
DECLARE @paramDefinition NVARCHAR(max);

if exists(select name from tempdb..sysobjects where name LIKE'#Columns%')
DROP TABLE #Columns;

CREATE TABLE #Columns (
    schema_id int,
    object_id int,
    column_id int,
    schemaName sysname,
    tableName sysname,
    columnName sysname,
    recordCnt bigint,
    MinValue int,
    MaxValue int,
    AvgValue int,
    nullCnt bigint,
    nullPct numeric(38,35) );

-- Set to the @lastSchema_id and @lastTable_id to NULL so that the first 
--  loop through the cursor the record count is generated.
SET @lastSchema_id = NULL;
SET @lastTable_id = NULL;

-- List of all the user schemas.tables.columns
--  in the database
DECLARE c_Cursor CURSOR FOR
SELECT
    schemas.schema_id
    , all_objects.object_id
    , all_columns.column_id
    , schemas.name AS schemaName
    , all_objects.name AS tableName
    , all_columns.name AS columnName
    , all_columns.is_nullable
FROM 
    sys.schemas
    INNER JOIN sys.all_objects
    ON schemas.schema_id = all_objects.schema_id
    AND all_objects.type = 'U'
    INNER JOIN sys.all_columns
    ON all_objects.object_id = all_columns.object_id

    INNER JOIN sys.types 
    ON all_columns.system_type_id = types.system_type_id
    AND all_columns.user_type_id = types.user_type_id

WHERE 
    types.name LIKE '%int%'
    OR types.name LIKE '%float%' 
    OR types.name LIKE '%decimal%'
    OR types.name LIKE '%numeric%'
    OR types.name LIKE '%real%'
    OR types.name LIKE '%money%'
ORDER BY 
    schemas.schema_id
    , all_objects.object_id
    , all_columns.column_id;

OPEN c_Cursor;

FETCH NEXT FROM c_Cursor
 INTO @schema_id
    , @object_id
    , @column_id
    , @schemaName
    , @tableName
    , @columnName
    , @isNullable;

-- Loop through the cursor
WHILE @@FETCH_STATUS = 0
BEGIN

    -- Get the record count for the table we are currently working on if this is
    --  the first time we are encountering the table.
    IF ( ( @schema_id <> @lastSchema_id ) OR ( @object_id <> @lastTable_id )
      OR ( @lastSchema_id IS NULL ) OR ( @lastTable_id IS NULL ) )
    BEGIN

        SET @SQL = N'SELECT @recordCount = COUNT(1) FROM ' + QUOTENAME(@schemaName) + N'.' + QUOTENAME(@tableName) + ';';
        SET @paramDefinition = N'@recordCount bigint OUTPUT';

        exec sp_executesql @SQL,
                           @paramDefinition,
                           @recordCount = @recordCount OUTPUT;

    END

    -- Get the min value for the table 

IF ( ( @schema_id <> @lastSchema_id ) OR ( @object_id <> @lastTable_id )
      OR ( @lastSchema_id IS NULL ) OR ( @lastTable_id IS NULL ) )
    BEGIN

        SET @SQL = N'SELECT @MinValue = MIN(' + QUOTENAME(@columnName) + N') FROM ' + QUOTENAME(@schemaName) + N'.' + QUOTENAME(@tableName) + ';';
        SET @paramDefinition = N'@MinValue int OUTPUT';

        exec sp_executesql @SQL,
                           @paramDefinition,
                           @MinValue = @MinValue OUTPUT;

    END

    --Get the max value for the table

    IF ( ( @schema_id <> @lastSchema_id ) OR ( @object_id <> @lastTable_id )
      OR ( @lastSchema_id IS NULL ) OR ( @lastTable_id IS NULL ) )
    BEGIN

        SET @SQL = N'SELECT @MaxValue = MAX(' + QUOTENAME(@columnName) + N') FROM ' + QUOTENAME(@schemaName) + N'.' + QUOTENAME(@tableName) + ';';
        SET @paramDefinition = N'@MaxValue int OUTPUT';

        exec sp_executesql @SQL,
                           @paramDefinition,
                           @MaxValue = @MaxValue OUTPUT;

    END

    --Get the avg value for the table
IF ( ( @schema_id <> @lastSchema_id ) OR ( @object_id <> @lastTable_id )
      OR ( @lastSchema_id IS NULL ) OR ( @lastTable_id IS NULL ) )
    BEGIN

        SET @SQL = N'SELECT @AvgValue = AVG(' + QUOTENAME(@columnName) + N') FROM ' + QUOTENAME(@schemaName) + N'.' + QUOTENAME(@tableName) + ';';
        SET @paramDefinition = N'@AvgValue int OUTPUT';

        exec sp_executesql @SQL,
                           @paramDefinition,
                           @AvgValue = @AvgValue OUTPUT;

    END



    -- If the column is NOT NULL, there is no reason to do a count
    --  Set the nullCnt and nullPct to 0
    IF ( @isNullable = 0 )
    BEGIN


        INSERT INTO #Columns
             ( [schema_id]
             , [object_id]
             , column_id
             , schemaName
             , tableName
             , columnName
             , recordCnt
             , nullCnt
             , nullPct
             ,MinValue
             ,MaxValue
             ,AvgValue )
        SELECT
             @schema_id
             , @object_id
             , @column_id
             , @schemaName
             , @tableName
             , @columnName
             , @recordCount
             , 0
             , 0
             , @MinValue
             , @MaxValue
             , @AvgValue
    END
    -- If the column is NULL, count the number of NULL fields in the table.
    ELSE
    BEGIN

        SET @SQL = N'SELECT @nullCnt = COUNT(1) FROM ' + QUOTENAME(@schemaName) + N'.' + QUOTENAME(@tableName) + 
                   N' WHERE ' + QUOTENAME(@columnName) + N' IS NULL;';
        SET @paramDefinition = N'@nullCnt bigint OUTPUT';

        PRINT @SQL;

        exec sp_executesql @SQL,
                           @paramDefinition,
                           @nullCnt = @nullCnt OUTPUT;

        INSERT INTO #Columns
             ( [schema_id]
             , [object_id]
             , column_id
             , schemaName
             , tableName
             , columnName
             , recordCnt
             , nullCnt
             , nullPct
             ,MinValue
             ,MaxValue
             ,AvgValue )
        SELECT
              @schema_id
             , @object_id
             , @column_id
             , @schemaName
             , @tableName
             , @columnName
             , @recordCount
             , @nullCnt
             -- USE NULLIF in case there are no recods in the table
             , ISNULL( @nullCnt * 1.0 / NULLIF( @recordCount, 0) * 100.0, 0 )
             , @MinValue
             , @MaxValue
             , @AvgValue

    END

    -- Set the @lastSchema_id and @lastTable_id so that on 
    --  the next loop, if it's the same table there is no 
    --  need to recount the columns for the table.
    SET @lastSchema_id = @schema_id;
    SET @lastTable_id = @object_id;

    FETCH NEXT FROM c_Cursor
     INTO @schema_id
        , @object_id
        , @column_id
        , @schemaName
        , @tableName
        , @columnName
        , @isNullable;

END;

CLOSE c_Cursor;
DEALLOCATE c_Cursor;

SELECT *
  FROM #Columns;

错误:

  • 您正在计算平均值、最小值和最大值,COUNT而不是正确的操作。
  • avg、min 和 max 未应用于正确的列,它始终是硬编码的 1。
  • 您正在计算平均值、最小值和最大值,但没有将它们插入临时表中。
于 2018-05-08T13:13:10.287 回答