Share via

T-SQL query error

amomen 381 Reputation points
2021-06-15T14:55:26.947+00:00

Hello everybody,

I have written the following query for SQL Server but an error occurs while executing it which is illogical and
does not make sense:

SELECT ac.name AS Column_Name, (SELECT COUNT(DISTINCT ac.name) FROM [Northwind].[Sales].[Orders])
        FROM [Northwind].sys.all_columns ac
        WHERE object_id = OBJECT_ID('[Northwind].[Sales].[Orders]')

The error is the following famous error:

Column 'Northwind.sys.all_columns.name' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

It is illogical because the aggregate function 'COUNT' belongs to the subquery, not to the main SELECT statement.
I also tried to trick SQL Server by rewriting the statement like below with 'MyFunction' function but I need to execute a dynamic SQL within that function which I figured out that it is not possible:

    SELECT ac.name AS Column_Name, MyFunction(ac.name) FROM [Northwind].[Sales].[Orders])
            FROM [Northwind].sys.all_columns ac
            WHERE object_id = OBJECT_ID('[Northwind].[Sales].[Orders]')

I also added the 'group by ac.name' clause to the first query which logically is not needed, for test purpose, and either of two scenarios occurs:

  • The following error occurs:

Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

Which is again illogical because the subquery never returns more than 1 value. That is absurd.

  • The result is identical for every ac.name in the result grid, which is wrong and unwanted

What can the possible solution and workaround be? I really appreciate your help.

Best regards,
Ali

Developer technologies | Transact-SQL
Developer technologies | Transact-SQL

A Microsoft extension to the ANSI SQL language that includes procedural programming, local variables, and various support functions.

0 comments No comments

Answer accepted by question author

  1. MelissaMa-msft 24,246 Reputation points Moderator
    2021-06-16T02:15:17.767+00:00

    Hi @amomen-8749,

    You could refer Viorel's solution if your version is SQL server 2017 and later.

    If have an old version, you could refer below using STUFF:

    declare @tablename varchar(max) = '[Northwind].[dbo].[Orders]'  
              
    declare @sql nvarchar(max)   
    select @sql= STUFF((  
    select ' union all select '+ quotename([name], '''')+' as Column_Name, count(distinct ', quotename([name]), ')*100.0/Count(*) as [crowdedness(in %)] '+  
            'from '+ @tablename  
    FROM sys.all_columns  
    WHERE object_id = OBJECT_ID(@tablename)  
    FOR XML PATH('') ), 1, 10, '')   
          
    exec(@sql)   
    

    Output:

    Column_Name	crowdedness(in %)  
    OrderID	100.000000000000  
    CustomerID	10.722891566265  
    EmployeeID	1.084337349397  
    OrderDate	57.831325301204  
    RequiredDate	54.698795180722  
    ShippedDate	46.626506024096  
    ShipVia	0.361445783132  
    Freight	96.265060240963  
    ShipName	10.843373493975  
    ShipAddress	10.722891566265  
    ShipCity	8.433734939759  
    ShipRegion	2.289156626506  
    ShipPostalCode	10.120481927710  
    ShipCountry	2.530120481927  
    

    In case you would like to list all columns of all tables in all databases in master, you could refer below and check whether it is a little helpful:

    DROP TABLE IF EXISTS #AllTables  
      
    SET NOCOUNT ON  
    CREATE TABLE #AllTables (DbName sysname,SchemaName sysname, TableName sysname)  
    DECLARE  
         @SearchDb nvarchar(200)  
        ,@SearchSchema nvarchar(200)  
        ,@SearchTable nvarchar(200)  
        ,@SQL nvarchar(4000)  
    SET @SearchDb='%%'  
    SET @SQL='select ''?'' as DbName, s.name as SchemaName, t.name as TableName from [?].sys.tables t inner join sys.schemas s on t.schema_id=s.schema_id  
    WHERE ''?'' LIKE '''+@SearchDb+'''  AND ''?'' NOT IN (''master'',''model'',''msdb'',''tempdb'',''SSISDB'')'      
      
    INSERT INTO #AllTables (DbName, SchemaName, TableName)  
        EXEC sp_msforeachdb @SQL  
    SET NOCOUNT OFF  
    SELECT * FROM #AllTables ORDER BY DbName, SchemaName, TableName  
    

    Best regards,
    Melissa


    If the answer is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


4 additional answers

Sort by: Most helpful
  1. Ronen Ariely 15,221 Reputation points
    2021-06-15T19:23:33.783+00:00

    Hi (again) :-)

    OK, so assuming I understand your request (even so I have no idea why you need this information), please check the following solution using simple UNPIVOTE

    ;with pvt as (  
     select   
      'OrderID'        = count(distinct [OrderID])         
     ,'CustomerID'     = count(distinct [CustomerID])      
     ,'EmployeeID'     = count(distinct [EmployeeID])      
     ,'OrderDate'      = count(distinct [OrderDate])       
     ,'RequiredDate'   = count(distinct [RequiredDate])    
     ,'ShippedDate'    = count(distinct [ShippedDate])     
     ,'ShipVia'        = count(distinct [ShipVia])         
     ,'Freight'        = count(distinct [Freight])         
     ,'ShipName'       = count(distinct [ShipName])        
     ,'ShipAddress'    = count(distinct [ShipAddress])     
     ,'ShipCity'       = count(distinct [ShipCity])        
     ,'ShipRegion'     = count(distinct [ShipRegion])      
     ,'ShipPostalCode' = count(distinct [ShipPostalCode])  
     ,'ShipCountry'    = count(distinct [ShipCountry])     
     from [Northwind]..[Orders]  
    )  
    SELECT Column_Name, Counting    
    FROM(  
     SELECT * FROM pvt  
    ) p    
    UNPIVOT(  
     Counting FOR Column_Name IN (  
     OrderID       ,  
     CustomerID    ,  
     EmployeeID    ,  
     OrderDate     ,  
     RequiredDate  ,  
     ShippedDate   ,  
     ShipVia       ,  
     Freight       ,  
     ShipName      ,  
     ShipAddress   ,  
     ShipCity      ,  
     ShipRegion    ,  
     ShipPostalCode,  
     ShipCountry     
     )    
    )AS unpvt;    
    GO  
    

    The result looks like this:

    105869-image.png

    And another option (which I like less for this case) is executing multiple queries and UNIOIN ALL

              select 'OrderID'        as Column_Name, count(distinct [OrderID])        as [Count] from [Northwind]..[Orders]   
    union all select 'CustomerID'     as Column_Name, count(distinct [CustomerID])     as [Count] from [Northwind]..[Orders]   
    union all select 'EmployeeID'     as Column_Name, count(distinct [EmployeeID])     as [Count] from [Northwind]..[Orders]   
    union all select 'OrderDate'      as Column_Name, count(distinct [OrderDate])      as [Count] from [Northwind]..[Orders]   
    union all select 'RequiredDate'   as Column_Name, count(distinct [RequiredDate])   as [Count] from [Northwind]..[Orders]   
    union all select 'ShippedDate'    as Column_Name, count(distinct [ShippedDate])    as [Count] from [Northwind]..[Orders]   
    union all select 'ShipVia'        as Column_Name, count(distinct [ShipVia])        as [Count] from [Northwind]..[Orders]   
    union all select 'Freight'        as Column_Name, count(distinct [Freight])        as [Count] from [Northwind]..[Orders]   
    union all select 'ShipName'       as Column_Name, count(distinct [ShipName])       as [Count] from [Northwind]..[Orders]   
    union all select 'ShipAddress'    as Column_Name, count(distinct [ShipAddress])    as [Count] from [Northwind]..[Orders]   
    union all select 'ShipCity'       as Column_Name, count(distinct [ShipCity])       as [Count] from [Northwind]..[Orders]   
    union all select 'ShipRegion'     as Column_Name, count(distinct [ShipRegion])     as [Count] from [Northwind]..[Orders]  
    union all select 'ShipPostalCode' as Column_Name, count(distinct [ShipPostalCode]) as [Count] from [Northwind]..[Orders]   
    union all select 'ShipCountry'    as Column_Name, count(distinct [ShipCountry])    as [Count] from [Northwind]..[Orders]  
    GO  
    

  2. Viorel 126.9K Reputation points
    2021-06-15T17:48:33.52+00:00

    Maybe this dynamic query will work for you:

    declare @tablename varchar(max) = '[Northwind]..[Orders]'
    
    declare @sql nvarchar(max) = 
      (select string_agg(
         concat('select ', quotename([name], ''''), ' as Column_Name, count(distinct ', quotename([name]), ') as [Count] ',
            'from ', @tablename),
         ' union all ')
    FROM sys.all_columns
    WHERE object_id = OBJECT_ID(@tablename))
    
    exec(@sql)
    

  3. Tom Phillips 17,786 Reputation points
    2021-06-15T17:00:43.097+00:00
    0 comments No comments

  4. Ronen Ariely 15,221 Reputation points
    2021-06-15T15:50:28.31+00:00

    Good day,

    It is illogical

    Actually your queries are totally illogical and make no sense. The errors are pretty clear.

    In your code you use aggregate function inside a sub-query on the main table out the sub-query and you select the column "name" from the main query. Since the aggregate is done on the main query and the column "name" is not part of the group by or aggregated columns then you get this error. This is very clear error.

    Try to execute the following query and you will get the same error

    SELECT COUNT(DISTINCT ac.name), ac.name
    FROM [Northwind].sys.all_columns ac
    

    Subquery returned more than 1 value

    please check the code. There is no SELECT in a sub-query and missing the open of brackets probably.

    Moreover, you did not provided the function so we cannot test the query. Make sure that this is a scalar function if you want to use it as a value in your query. If this is a table function then again, this is a very clear error that self-explanatory error.

    It will be mush simpler to help you understand how to write the query if you can explain what you want to get and what is the expected result.


Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.