2016-12-23 4 views
0

Привет У меня есть таблица Timelogs имея с колоннами (идентификатор, начальный промежуток, EndTime, user_id, CLIENT_ID, PROJECT_ID, TASK_ID, TotalHours)Лучший способ получить сложные данных SQL (вопрос производительности)

мне нужно вывода Имея столбцы (Client , проект, задачи, NoOfResources, TotalTime) с projectids, taskids, datefrom, datetill фильтров выходных образцов и структуры таблиц приведены ниже

enter image description here

Здесь user_id, cLIENT_ID, TASK_ID, pROJECT_ID внешние ключи с пользователями, клиентами , задачи, проекты

Здесь # ресурсов является количество пользователей

Я делаю это с помощью хранимой процедуры:

ALTER procedure [dbo].[GetProjectUtilizationReport] 
    (@DateFrom datetime =null, 
    @DateTill datetime = null, 
    @TaskTypeIds nvarchar(max) = null, 
    @TaskIds nvarchar(max) = null, 
    @UserIds nvarchar(max) = null, 
    @ProjectIds nvarchar(max) = null) 
AS 
BEGIN 
    CREATE TABLE #TempTable(id int, 
          ProjectId int, 
          ClientId int, 
          UserId int, 
          TaskId int, 
          TotalHours numeric(18,2), 
          StartTime datetime, 
          TaskTypeId int) 

    --- create a temp table with data dump 
    INSERT INTO #TempTable(Id, ProjectId, ClientId, UserId, TaskId, TotalHours, StartTime, TaskTypeId) 
     SELECT 
      tl.id,Project_Id, Client_Id, 
      User_Id, Task_Id, TotalHours, 
      StartTime, TaskType_Id 
     FROM 
      TimeLogs tl 
     JOIN 
      Tasks t ON tl.Task_Id = t.Id 

    --apply filter to temp table 
    IF (@DateFrom IS NOT NULL) 
     DELETE FROM #TempTable 
     WHERE StartTime < @DateFrom 

    IF (@DateTill IS NOT NULL) 
     DELETE FROM #TempTable 
     WHERE StartTime > @DateTill 

    IF (@TaskTypeIds IS NOT NULL) 
     DELETE FROM #TempTable 
     WHERE TaskTypeId NOT IN (SELECT Item FROM dbo.SplitString(@TaskTypeIds, ',')) 

    IF (@TaskIds IS NOT NULL) 
     DELETE FROM #TempTable 
     WHERE TaskId NOT IN (SELECT Item FROM dbo.SplitString(@TaskIds, ',')) 

    IF (@UserIds IS NOT NULL) 
     DELETE FROM #TempTable 
     WHERE UserId NOT IN (SELECT Item FROM dbo.SplitString(@UserIds, ',')) 

    IF (@ProjectIds IS NOT NULL) 
     DELETE FROM #TempTable 
     WHERE ProjectId NOT IN (SELECT Item FROM dbo.SplitString(@ProjectIds, ',')) 

    --finaly select data 
    SELECT 
     p.Name as Project, c.Name as Client, 
     tl.TaskId, t.Name as Task, 
     SUM(TotalHours) as Totalhours, 
     COUNT(DISTINCT tl.UserId) as NoOfResources, 
     c.Id as ClientId 
    FROM 
     #TempTable tl 
    JOIN 
     Tasks t ON tl.TaskId = t.Id 
    JOIN 
     Clients c ON c.Id = tl.ClientId 
    JOIN 
     Projects p ON tl.ProjectId = p.Id 
    GROUP BY 
     tl.TaskId, c.id, c.Name, p.Name, t.Name 

    --drop temp table 
    DROP TABLE #TempTable 
END 

Я думаю, что может быть гораздо лучше подход - что-то вроде вида и т.д., но у меня нет есть идеи.

мая поместить данные в другой таблице на вставке и т.д.

Пожалуйста, введите свои рекомендации показывают, что я могу получить результаты так же быстро, как Возможное.

+0

Вы предоставили ожидаемый результат. Но нет данных о выборке. – Viki888

+0

Привет, я добавил другой снимок экрана и столбец с _ являются иностранными ключами – jitender

+0

Можете ли вы поверить, что люди в SO предоставляют вам решение без надлежащих данных образца? Мы не знаем, для чего 'Client_Id' принадлежит' Nokia' в ваших данных таблицы. Также предоставляйте образцы данных как текст вместо изображения, так как нам будет легко подготовить образцы данных и попытаться решить проблему для вас. – Viki888

ответ

2

Я часто стараюсь избегать #tables, где я могу.

SELECT c.Name AS Client, p.Name AS Project, t.Name AS Task, COUNT(DISTINCT tl.User_Id) AS NoOfResources, SUM(TotalHours) AS Totalhours   
FROM TimeLogs tl 
INNER JOIN Tasks t ON tl.Task_Id =t.Id 
INNER JOIN Clients c ON c.Id =tl.Client_Id 
INNER JOIN Projects p ON tl.Project_Id =p.Id 
INNER JOIN (SELECT Item FROM dbo.SplitString(ISNULL(@UserIds, ''), ',')) users ON users.Item = tl.User_Id OR @UserIds IS NULL 
INNER JOIN (SELECT Item FROM dbo.SplitString(ISNULL(@TaskTypeIds, ''), ',')) tasktypes ON tasktypes.Item = tl.TaskType_Id OR @TaskTypeIds IS NULL 
INNER JOIN (SELECT Item FROM dbo.SplitString(ISNULL(@TaskIds, ''), ',')) tasks ON tasks.Item = tl.Task_Id OR @TaskIds IS NULL 
INNER JOIN (SELECT Item FROM dbo.SplitString(ISNULL(@ProjectIds, ''), ',')) projects ON projects.Item = tl.Project_Id OR @ProjectIds IS NULL 
WHERE (@DateFrom IS NULL OR StartTime < @DateFrom) 
AND (@DateTill IS NULL OR StartTime > @DateTill) 
GROUP BY c.Id, c.Name, p,Id, p.Name, t.Id, t.Name 
+0

Спасибо @Stephen, который отлично работает на самом деле, много тесто, а затем меня, но как насчет производительности в случае больших данных, возьмите миллионы записей в этой таблице. – jitender

+0

@jitender вы можете протестировать Это. но я обнаружил, что #tables являются ресурсоемкими – Stephen

+0

Да, я согласен с вами в этом случае, но я не настолько силен в sql, и ваше решение даст мне большую работоспособность, но я думаю, что может быть какое-то решение производительности теста – jitender