【问题标题】:Count records using Date filter related tables SQL Server使用日期过滤器相关表 SQL Server 计数记录
【发布时间】:2021-06-29 23:54:10
【问题描述】:

我正在尝试计算两个日期(日历表)和工作日(agenda_user 表)之间每个用户的报告数量(report_user 表)。

这是我的表格的图表:

日历表:

 DATE         Year       Month
---------------------------------
2020-01-01      2020      1
2020-01-02      2020      1
2020-01-03      2020      1
2020-01-04      2020      1

AGENDA_USER 表:

ID_USER        DATE         Value
---------------------------------
1           2020-01-01       1
2           2020-01-01       1
1           2020-01-02       0
2           2020-01-02       1

用户表:

ID_USER        Name     
-------------------------
1              Jack
2              Robert

Report_Result 表:

ID_USER        Date          Result
-----------------------------------
1             2020-01-01      good
1             2020-01-01      good
2             2020-01-01      bad
2             2020-01-01      good
2             2020-01-02      good
2             2020-01-02      good

我正在尝试使用 SQL 查询查找结果

ID_USER        Date          Number of report     Day work      report/work
---------------------------------------------------------------------------
1             2020-01-01            2                1               2/1 = 2
2             2020-01-01            2                1                1
1             2020-01-02            0                0                0
2             2020-01-02            2                1                2
SELECT 
    REPORT_USER.ID_USER, 
    COUNT(ID_USER) AS result
FROM [DB].[dbo].REPORT_USER AS report,
JOIN [DB].[dbo].[USER] AS [USER]
     ON [USER].ID_USER = report.ID_USER
JOIN [DB].[dbo].AGENDA_USER AS agenda
     ON agenda.ID_USER = report.ID_USER
WHERE CAST(agenda.[Date] AS DATE) >= '2020-09-01'
    AND CAST(agenda.[Date] AS DATE) <= '2021-07-28'
    AND [USER].ID_user = 1167
GROUP BY 
    report.ID_VENDEUR;

【问题讨论】:

  • 到目前为止您尝试过什么?为什么它不起作用?实现预期结果的逻辑是什么?你在这里有什么问题?您的“问题”中没有明确的问题或问题陈述(关于您未共享的代码)。 Stack Overflow 不是免费的编码服务;不要把它当作一个。
  • 仅供参考,是的CAST({ColumnName} AS date) SARGable,但它isn't a good idea。使用&gt;=&lt;logic。
  • 把你的目标分解成碎片。 “报告数量”是什么意思?它是给定时间段/用户的 report_user 中所有行的总数吗?结果列中的值会影响计数吗?编写正确执行此操作的查询。然后重复“日常工作” - 公式是什么?你需要什么逻辑来计算。我认为您需要以某种方式外部加入,但不太了解您的目标。
  • @Larnu 我遇到的问题是我无法将agenda_user 表中的日期与report_result 表中的日期联系起来
  • 为什么不呢?加入date 列有什么问题?

标签: sql sql-server database powerbi


【解决方案1】:

我不完全确定我理解你的问题,但我认为我已经相当接近了,所以这是一个开始,指出我的无效假设,我们可以改进。更多数据,尤其是议程和报告中的数据,确实会有所帮助。下面是一个解释(加上代码中的注释)。

整个流程是生成您想要报告的日期/人员列表 (cteUserDays),生成每个用户在每个日期生成的报告数量列表 (cteReps),生成谁在哪些天工作的列表(cteWork),然后使用 LEFT OUTER JOIN 将所有 3 个部分连接在一起,以便报告涵盖所有日期的所有工作人员。 编辑:添加 cteRepRaw ,其中 DATETIME 转换为 DATE 并过滤掉“坏”报告。分组和计数仍然发生在 cteReps 中,但加入 cteUserDays 不存在,因为如果有 NULL,它会加 1 来计数。

DECLARE @Cal TABLE (CalDate DATETIME, CalYear int, CalMonth int)
DECLARE @Agenda TABLE (UserID int, CalDate DATE, AgendaVal int)
DECLARE @User TABLE (UserID int, UserName nvarchar(50))
DECLARE @Reps TABLE (UserID int, CalDate DATETIME, RepResult nvarchar(50))

INSERT INTO @Cal(CalDate, CalYear, CalMonth)
VALUES ('2020-01-01', 2020, 1), ('2020-01-02', 2020, 1), ('2020-01-03', 2020, 1), ('2020-01-04', 2020, 1)

INSERT INTO @Agenda(UserID, CalDate, AgendaVal)
VALUES (1, '2020-01-01', 1), (2, '2020-01-01', 1), (1, '2020-01-02', 0), (2, '2020-01-02', 1)

INSERT INTO @User (UserID , UserName )
VALUES (1, 'Jack'), (2, 'Robert')

INSERT INTO @Reps (UserID , CalDate , RepResult )
VALUES (1, '2020-01-01', 'good'), (1, '2020-01-01', 'good')
    , (2, '2020-01-01', 'bad'), (2, '2020-01-01', 'good')
    , (2, '2020-01-02', 'good'), (2, '2020-01-02', 'good')


; with cteUserDays as (
    --First, you want zeros in your table where no reports are, so build a table for that
    SELECT CONVERT(DATE, D.CalDate) as CalDate --EDIT add CONVERT here
      , U.UserID FROM @Cal as D CROSS JOIN @User as U
    WHERE D.CalDate >= '2020-01-01' AND D.CalDate <= '2021-07-28'
    --EDIT Watch the <= date here, a DATE is < DATETIME with hours of the same day
), cteRepRaw as (--EDIT Add this CTE to convert DATETIME to DATE so we can group on it
    --Map the DateTime to a DATE type so we can group reports from any time of day
    SELECT R.UserID 
        , CONVERT(DATE, R.CalDate) as CalDate --EDIT add CONVERT here
        , R.RepResult
    FROM @Reps as R 
    WHERE R.RepResult='good' --EDIT Add this test to only count good ones
), cteReps as (
    --Get the sum of all reports for a given user on a given day, though some might be missing (fill 0)
    SELECT R.UserID , R.CalDate , COUNT(*) as Reports --SUM(COALESCE(R.RepResult, 0)) as Reports
    FROM cteRepRaw as R--cteUserDays as D 
        --Some days may have no reports for that worker, so use a LEFT OUTER JOIN
        --LEFT OUTER JOIN cteRepRaw as R on D.CalDate = R.CalDate AND D.UserID = R.UserID
    GROUP BY R.UserID , R.CalDate 
) , cteWork as (
    --Unclear what values "value" in Agenda can take, but assuming it's some kind of work 
    -- unit, like "hours worked" or "shifts" so add them up 
    SELECT A.UserID , A.CalDate, SUM(A.AgendaVal) as DayWork FROM @Agenda as A 
    WHERE A.CalDate >= '2020-01-01' AND A.CalDate <= '2021-07-28'
    GROUP BY A.CalDate, A.UserID 
) 
SELECT D.UserID , D.CalDate, COALESCE(R.Reports, 0) as Reports, W.DayWork 
    --NOTE: While it's probably a mistake to credit a report to a day a worker had
    --no shifts, it could happen and would throw an error so check
    , CASE WHEN W.DayWork > 0 THEN R.Reports / W.DayWork ELSE 0 END as RepPerWork
FROM cteUserDays as D 
    LEFT OUTER JOIN cteReps as R on D.CalDate=R.CalDate AND R.UserID = D.UserID 
    LEFT OUTER JOIN cteWork as W on D.UserID = W.UserID AND D.CalDate = W.CalDate 
ORDER BY CalDate , UserID 

首先,根据您的 OP“议程”中的 cmets 表示用户何时工作,您没有说明它的结构,所以我假设它可以在给定的一天为给定的人有多个条目(即4 小时轮班和 8 小时轮班),所以我将它们加起来得到总工作量(cteWork)。我还假设如果有人不工作,您就无法为他们提供报告。我对此进行了检查,但通常我希望您的数据验证器预先筛选出来。

其次,我假设每条记录有 1 个报告,给定用户每天可以有多个。您已经在给定的内容中找到了,但这对这个解决方案很重要,所以我重申一下,以防其他人稍后阅读。

第三,我假设您希望为所有用户报告所有天数,我通过在用户和天数 (cteUserDays) 之间生成交叉连接来保证这一点

【讨论】:

  • 感谢您的时间并帮助我接近结果。计数结果不起作用我需要调整报告和日历表中的日期,因为它们是 DateTime 格式,而议程是 Date 格式?
  • OK @SoufianeS 我对其进行了调整以转换日期,并修复了计数因错误地计算 NULL 而导致的问题,试试这个,让我知道它现在是否正确。
  • 它有效!非常感谢您的宝贵帮助:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-23
  • 1970-01-01
  • 1970-01-01
  • 2020-11-20
相关资源
最近更新 更多