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

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.

Was this answer helpful?


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  
    

    Was this answer helpful?


  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)
    

    Was this answer helpful?


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

    Was this answer helpful?

    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.

    Was this answer helpful?


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.