0

I have a table called tasks, which lists different tasks a worker can complete. Then i have a relationship table that links a completed task to a worker. I'm trying to write query that groups the tasks into a list based on the worker id, but the query gives me the following error (see below).

Column 'mater.dbo.worker_task_completion.FK_task_id' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

Tables

CREATE TABLE [dbo].[tasks]
(
    [task_id] [int] IDENTITY(1,1) NOT NULL,
    [name] [nvarchar](50) NOT NULL,
    [icon] [nvarchar](max) NULL,
    [isActive] [int] NOT NULL,
    [time] [int] NOT NULL,
    CONSTRAINT [PK_tasks] PRIMARY KEY CLUSTERED 
(
    [task_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]



CREATE TABLE [dbo].[worker_task_completion]
(
    [FK_worker_id] [int] NOT NULL,
    [FK_task_id] [int] NOT NULL,
    [update_date] [datetime] NOT NULL,
    CONSTRAINT [PK_worker_task_completion] PRIMARY KEY CLUSTERED 
(
    [FK_worker_id] ASC,
    [FK_task_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

Query

SELECT top 100 wtc.FK_worker_id, 
                tasks = Stuff((SELECT ', ' + dbo.tasks.NAME 
                                FROM   dbo.tasks
                               WHERE  dbo.tasks.task_id = 
                                     wtc.FK_task_id
                               FOR xml path ('')), 1, 1, '')
        FROM   dbo.worker_task_completion AS wtc 
                LEFT JOIN dbo.tasks AS tc 
                       ON tc.task_id = wtc.fk_task_id
        -- WHERE  wtc.FK_worker_id IN ()
GROUP  BY wtc.FK_worker_id
AJ_
  • 3,787
  • 10
  • 47
  • 82
  • 2
    What about the error don't you understand? It's quite clear on what the problem is. – Thom A Jul 23 '18 at 15:35
  • Which aggregate functions does your SELECT statement use? – openshac Jul 23 '18 at 15:36
  • 1
    Why did you use `GROUP BY` without using any aggregate function? – D-Shih Jul 23 '18 at 15:36
  • Am i not aggregating over the dbo.tasks.NAME column with stuff ? – AJ_ Jul 23 '18 at 15:38
  • 1
    No, you're not. STUFF/FOR XML PATH aid aggregation but they are not aggregates. What version of SQL Server are you using? – Aaron Bertrand Jul 23 '18 at 15:41
  • @AaronBertrand, well then that is my bad. 2016 – AJ_ Jul 23 '18 at 15:42
  • A full list of Aggregate Function can be found in the documentation: [Aggregate Functions (Transact-SQL)](https://learn.microsoft.com/en-us/sql/t-sql/functions/aggregate-functions-transact-sql?view=sql-server-2017). Neither `STUFF` or `FOR XML PATH` are mentioned. – Thom A Jul 23 '18 at 15:42
  • @AJ_ What's the purpose of `GROUP BY`??? I don't see any aggregation. – Eric Jul 23 '18 at 15:44
  • That's too bad, [`STRING_AGG`](https://learn.microsoft.com/en-us/sql/t-sql/functions/string-agg-transact-sql?view=sql-server-2017) solves this problem really well. – Aaron Bertrand Jul 23 '18 at 15:49

2 Answers2

1

Hmmm. You cannot use a non-aggregated column for the correlation clause. The solution is to move the JOIN into the subquery:

SELECT top 100 wtc.FK_worker_id, 
       stuff((SELECT ', ' + t.NAME 
              FROM dbo.worker_task_completion wtc2 JOIN
                   dbo.tasks t
                   ON t.task_id = wtc2.FK_task_id
              WHERE wtc2.FK_worker_id = wtc.FK_worker_id
              FOR xml path ('')
             ), 1, 2, ''
            ) as tasks
FROM (SELECT DISTINCT wtc.FK_worker_id
      FROM dbo.worker_task_completion wtc 
     ) wtc
        -- WHERE  wtc.FK_worker_id IN ()

Note that I changed the second argument for STUFF(). Presumably, you want to remove the space as well as the comma.

Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786
1
;WITH CTE_worker_task_completion
 AS (SELECT [FK_worker_id]
           ,[FK_task_id]
     FROM [dbo].[worker_task_completion])

 ------------------------------------------
 SELECT [WT].[FK_worker_id]
       ,[Task]=Stuff(
        (
        SELECT ', '+[T].[Name]   
        FROM [dbo].[tasks] AS [T]
        INNER JOIN CTE_worker_task_completion AS [WTC]
              ON [T].[Task_ID]=[WTC].[Task_ID]
      Where [WT].[Worker_ID]=[WTC].[Worker_ID]
        ORDER BY [T].[Name] FOR XML PATH('')
        ),1,1,'')
 FROM CTE_worker_task_completion AS [WT]
 GROUP BY [WT].[FK_worker_id];
J a c k
  • 11
  • 2