使用相同条件但不同列并使用聚合函数编写查询

Write query with same conditions but different columns and using aggregate functions

我正在制作一个系统,可以根据客户需求分配分析师。我编写了一个程序来搜索要分配给需求的理想分析师。

主要表格有:

寻找分析师的规则如下:

代码如下:

    DECLARE @totalRequirementsAnalysts int
    DECLARE @idAnalyst int = null 
    
    SELECT @totalRequirementsAnalysts =count(distinct(a.requirements)) 
    FROM ( 
        SELECT 
            a.id,count(r.id) requirements
        FROM
            grc_analyst a
            INNER JOIN  grc_analyststate ea     ON a.id_analyststate = ea.id AND ea.code = 'A'
            INNER JOIN  grc_analyst_category ac ON a.id = ac.id_analyst 
            INNER JOIN  grc_category c              ON c.id = ac.id_category AND c.code = 'SOAP'        
            LEFT JOIN   grc_requirement r           ON a.id = r.id_analyst AND r.id_requirementstate in (
                SELECT id from grc_requirementstate er where er.code IN ('AS','ER','DL','DC') 
            )
        group by a.id 
    ) a
    
    
    IF  (@totalRequirementsAnalysts = 1)
    BEGIN 
        PRINT 'Analysts have the same amount of requirements assigned'
    
        SET @idAnalyst = (
            SELECT a.id from (
                SELECT TOP(1)
                    a.id,avg (DATEDIFF(DAY,getdate(),r.due_date))average_due_date
                FROM
                    grc_analyst a
                    INNER JOIN  grc_analyststate ea     ON a.id_analyststate = ea.id AND ea.code = 'A'
                    INNER JOIN  grc_analyst_category ac ON a.id = ac.id_analyst 
                    INNER JOIN  grc_category c              ON c.id = ac.id_category AND c.code = 'SOAP'        
                    LEFT JOIN   grc_requirement r           ON a.id = r.id_analyst AND r.id_requirementstate in (
                        SELECT id from grc_requirementstate er where er.code IN ('AS','ER','DL','DC') 
                    )
                group by a.id 
                order by average_due_date DESC
            ) a
        )
    
    END
    ELSE
    BEGIN
        PRINT 'Analysts have different number of requirements assigned'
        SET @idAnalyst = (
            SELECT a.id from (
                SELECT TOP(1)
                    a.id,count(r.id) requirements
                FROM
                    grc_analyst a
                    INNER JOIN  grc_analyststate ea     ON a.id_analyststate = ea.id AND ea.code = 'A'
                    INNER JOIN  grc_analyst_category ac ON a.id = ac.id_analyst 
                    INNER JOIN  grc_category c              ON c.id = ac.id_category AND c.code = 'SOAP'        
                    LEFT JOIN   grc_requirement r           ON a.id = r.id_analyst AND r.id_requirementstate in (
                        SELECT id from grc_requirementstate er where er.code IN ('AS','ER','DL','DC') 
                    )
                group by a.id 
                order by requirements ASC
            ) a
        )
    END
    
    SELECT ga.id from grc_analyst ga where ga.id = @idAnalyst

如您所见,我使用了三个查询,但所有三个查询的“来自”部分都是相同的(具有相同条件的相同连接表)。此过程符合规则并且有效,但我想减少查询次数,因为存在重复的代码。

提前致谢!

这有帮助吗?

WITH base AS
(
  SELECT 
    a.id,
    count(r.id) requirements,
    avg (DATEDIFF(DAY,getdate(),r.due_date)) average_due_date
  FROM grc_analyst a
  JOIN grc_analyststate ea     ON a.id_analyststate = ea.id AND ea.code = 'A'
  JOIN grc_analyst_category ac ON a.id = ac.id_analyst 
  JOIN grc_category c          ON c.id = ac.id_category AND c.code = 'SOAP'        
  LEFT JOIN grc_requirement r  ON a.id = r.id_analyst
  JOIN grc_requirementstate es ON r.id_requirementstate IS NULL OR 
                                  (r.id_requirementstate IS NOT NULL 
                                    AND r.id_requirementstate = er.id 
                                    AND er.code IN ('AS','ER','DL','DC') 
                                  )
  group by a.id 
)
-- etc

如果您不喜欢 CTE,那么您可以使用上面的视图。

此外,当 grc_requirement table 的左连接在日期差异平均值上为空时,我也不知道规则是什么。如果这个结果是错误的,那应该被修复。

为避免重复代码,创建查询公共部分的视图,然后在您的 3 个查询中使用它,例如

CREATE VIEW dbo.grc_analyst_view
AS
SELECT a.id
    , COUNT(r.id) requirements
    , AVG(DATEDIFF(DAY,GETDATE(),r.due_date)) average_due_date
FROM grc_analyst a
INNER JOIN grc_analyststate ea ON a.id_analyststate = ea.id AND ea.code = 'A'
INNER JOIN grc_analyst_category ac ON a.id = ac.id_analyst 
INNER JOIN grc_category c ON c.id = ac.id_category AND c.code = 'SOAP'        
LEFT JOIN grc_requirement r ON a.id = r.id_analyst AND r.id_requirementstate in (
    SELECT id
    FROM grc_requirementstate er
    WHERE er.code IN ('AS','ER','DL','DC') 
)
GROUP BY a.id;
GO

-- QUERY 1
SELECT @totalRequirementsAnalysts = COUNT(DISTINCT(requirements)) 
FROM dbo.grc_analyst_view;

-- QUERY 2
SELECT TOP(1) id
FROM dbo.grc_analyst_view
ORDER BY average_due_date DESC

-- QUERY 3
SELECT TOP(1) id
FROM dbo.grc_analyst_view
ORDER BY requirements ASC;

实际上我相信你可以用一个查询完成你想要的,利用 window 函数 FIRST_VALUE 和一个 sub-query 你可以获得你想要的值而无需完全重复查询。这也应该表现得更好。

原来你不能在COUNT OVER ()中使用DISTINCT所以我们必须使用CTECROSS APPLY来代替。

with cte as (
  SELECT a.id
      , COUNT(DISTINCT r.id) Requirements
      , AVG(DATEDIFF(DAY,GETDATE(),r.due_date)) average_due_date
  FROM grc_analyst a
  INNER JOIN grc_analyststate ea ON a.id_analyststate = ea.id AND ea.code = 'A'
  INNER JOIN grc_analyst_category ac ON a.id = ac.id_analyst 
  INNER JOIN grc_category c ON c.id = ac.id_category AND c.code = 'SOAP'        
  LEFT JOIN grc_requirement r ON a.id = r.id_analyst AND r.id_requirementstate in (
      SELECT id
      FROM grc_requirementstate er
      WHERE er.code IN ('AS','ER','DL','DC') 
  )
  GROUP BY a.id
)
SELECT TOP 1 @idAnalyst = CASE WHEN N.DistinctRequirements = 1 THEN FIRST_VALUE(X.id) OVER (ORDER BY average_due_date ASC) ELSE FIRST_VALUE(X.id) OVER (ORDER BY Requirements ASC) END
FROM cte X
CROSS APPLY (
  SELECT COUNT(DISTINCT Requirements) DistinctRequirements
  FROM cte
) N;
-- While one should normally use an 'order by' clause with 'top' it is meaningless in this case as all rows return the same.

如果需要打印选择了哪个选项,则将 requirements 计数分配给一个变量并在您的 IF 语句中使用它。