如何列出各个列,其中每个列包含一个 id 计数,其中每列中的 id 不在 MySQL 中每列的不同表中

Posted

技术标签:

【中文标题】如何列出各个列,其中每个列包含一个 id 计数,其中每列中的 id 不在 MySQL 中每列的不同表中【英文标题】:How to list individual columns where each contains a count of ids where the ids in each column are 'not in' a different table for each column in MySQL 【发布时间】:2018-03-29 22:47:34 【问题描述】:

我正在尝试运行以下查询,以确定在特定日期我在某个区域有多少尚未预订的可用供应。为此,我按区域和可用天数生成所有工人的表格,并使用“位置”来确保他们“不在”当天确认的预订表格中。

我有两个问题:

    这只能给我 1 天的剩余可用供应。我希望能够显示一系列天的剩余可用供应。例如。未来三天第 1 天、第 2 天和第 3 天的剩余可用供应。这意味着我必须迭代地将我的工人列表与每天的预订表进行比较。所以 col1 将计算工人 id '不在' Day1 的预订表中并且工人在 Day1s 工作,col2 将计算工人 id '不在' Day2 的预订表中并且工人在 Day2s 工作,......等等。

    李>

    这是一个较小的问题。给定下面的代码,如果可用供应的计数为 0,则该区域行不在结果表中。我曾尝试在计数上使用 IFNULL ,但这没有用。因此,我必须在它和一个查询之间创建一个联合,该查询列出所有具有 0 值的区域,然后选择每个具有最大值的区域。有没有更好的方法来做到这一点?

[daterange_start] 字段是由仪表板的最终用户替换的过滤字段。

select 
    area, 
    MAX(man_days_remaining)
from (
select doa.zip_code as area, count(w.user_ptr_id) as man_days_remaining
from domestic_worker w 
left join domestic_worker_worker_operating_areas dwoa 
    on w.user_ptr_id = dwoa.worker_id 
left join geography_operatingarea doa 
    on doa.id = dwoa.operatingarea_id 
left join domestic_worker_days_available d 
    on w.user_ptr_id = d.worker_id 
left join geography_city c 
    on c.id = w.worker_city_id
where w.user_ptr_id not in (
    select w.user_ptr_id 
    from booking_booking b 
    left join domestic_jobcard j 
    on b.id = j.booking_id 
    left join domestic_worker w 
    on w.user_ptr_id = j.worker_id 
    where date(b.appointment_datetime) = date([daterange_start]) 
    and b.booking_status = 'confirmed' 
    and w.user_ptr_id is not null) 
and weekday([daterange_start]) + 1 = d.weekday_id
group by 1
UNION
select doa.zip_code as 'Area', '0', null
from geography_operatingarea doa
where doa.active = 1
) t
group by 1
order by 1 asc

【问题讨论】:

要获取日期范围,您可以在 where 中使用 between 子句,并将日期添加到 group bycolumns由查询返回。 如果您编辑问题并添加所涉及表的架构,则可以完成更具体的答案。为了创建正确的查询,了解某些列的类型很重要。 另外,我怀疑 UNION 的原因是包含第一个查询中没有行的区域。我建议使用左连接来包含这些行。 【参考方案1】:

规范并不完全清楚。架构定义、示例数据和预期输出示例将大大有助于阐明它。

所以,我们只是猜测。

我的猜测是这样的东西可以满足要求:

SELECT t.zip_code AS area
     , MAX(IF(t.i=0,man_days_remaining,0)) AS d0_mdr  -- day 0 man days remaining
     , MAX(IF(t.i=1,man_days_remaining,0)) AS d1_mdr  -- day 1 man days remaining
     , MAX(IF(t.i=2,man_days_remaining,0)) AS d2_mdr  -- day 2 man days remaining
     , MAX(IF(t.i=3,man_days_remaining,0)) AS d3_mdr  -- day 3 man days remaining
 FROM (
        SELECT doa.zip_code
             , n.i
             , COUNT(DISTINCT w.user_ptr_id) AS man_days_remaining
          FROM ( SELECT DATE([daterange_start]) + INTERVAL 0 DAY AS dt ) i
         CROSS
          JOIN ( SELECT 0 AS i
                 UNION ALL SELECT 1
                 UNION ALL SELECT 2
                 UNION ALL SELECT 3
                 UNION ALL SELECT NULL
               ) n
          JOIN geography_operatingarea doa
            ON doa.active = 1
          LEFT
          JOIN domestic_worker_worker_operating_areas dwoa
            ON dwoa.operatingarea_id = doa.id
          LEFT
          JOIN domestic_worker w
            ON w.user_ptr_id = dwoa.worker_id
          LEFT
          JOIN domestic_worker_days_available d
            ON d.worker_id = w.user_ptr_id
           AND d.weekday_id = WEEKDAY(i.dt + INTERVAL n.i DAY) + 1

            -- anti-join confirmed booking
          LEFT
          JOIN domestic_jobcard dj
            ON dj.worker_id = d.worker_id
          LEFT
          JOIN booking_booking bb
            ON bb.id = dj.booking_id
           AND bb.booking_status = 'confirmed'
           AND DATE(bb.appointment_datetime) = i.dt + INTERVAL n.i DAY
         WHERE bb.id IS NULL

         GROUP
            BY doa.zip_code
             , n.i
        ) t
  GROUP BY t.zip_code

这是使用内联视图 (n) 返回整数值 0 到 3。我们将把它添加到 [daterange_start] 以检查四个日期,从 [daterange_start] 开始。

然后我们可以将该集合加入所有“活跃”的 doa。

外连接获取在这些日期可用的所有domestic_worker 的集合。

然后我们可以使用反连接模式来排除任何domestic_worker 确认预订的日期。

然后我们可以获得每天可用的工人数量。

边缘情况是一个 doa,其中该区域的所有工作人员都已预订了所有四天,查询不会返回该 doa。我们可以做一个 hack,为每个 zip_code 包含额外的行...保证不匹配任何工作人员或预订的行,并且不会包含在任何计数中。一种快速的方法是在我们生成的整数集中包含一个 NULL 值。

然后我会将结果包装为内联视图,然后使用条件聚合来获取每个邮政编码的单行中每天剩余的工作日数。

这种方法可以扩展到任意天数,方法是向生成的集合添加额外的整数 (4,5,...),并在外部查询的 SELECT 列表中添加表达式。

这可能不满足规范。我对它的理解非常有限,但这是我的处理方式。


作为反连接的替代方案,我们可以使用带有相关子查询的NOT EXISTS 谓词:

SELECT t.zip_code AS area
     , MAX(IF(t.i=0,man_days_remaining,0)) AS d0_mdr  -- day 0 man days remaining
     , MAX(IF(t.i=1,man_days_remaining,0)) AS d1_mdr  -- day 1 man days remaining
     , MAX(IF(t.i=2,man_days_remaining,0)) AS d2_mdr  -- day 2 man days remaining
     , MAX(IF(t.i=3,man_days_remaining,0)) AS d3_mdr  -- day 3 man days remaining
 FROM (
        SELECT doa.zip_code
             , n.i
             , COUNT(DISTINCT w.user_ptr_id) AS man_days_remaining
          FROM ( SELECT DATE([daterange_start]) + INTERVAL 0 DAY AS dt ) i
         CROSS
          JOIN ( SELECT 0 AS i
                 UNION ALL SELECT 1
                 UNION ALL SELECT 2
                 UNION ALL SELECT 3
                 UNION ALL SELECT NULL
               ) n
          JOIN geography_operatingarea doa
            ON doa.active = 1
          LEFT
          JOIN domestic_worker_worker_operating_areas dwoa
            ON dwoa.operatingarea_id = doa.id
          LEFT
          JOIN domestic_worker w
            ON w.user_ptr_id = dwoa.worker_id
          LEFT
          JOIN domestic_worker_days_available d
            ON d.worker_id = w.user_ptr_id
           AND d.weekday_id = WEEKDAY(i.dt + INTERVAL n.i DAY) + 1

            -- exclude matches using NOT EXISTS with correlated subquery
         WHERE NOT EXISTS 
               ( SELECT 1
                   FROM domestic_jobcard dj
                   JOIN booking_booking bb
                     ON bb.id = dj.booking_id
                    AND bb.booking_status = 'confirmed'
                    AND DATE(bb.appointment_datetime) = i.dt + INTERVAL n.i DAY
                  WHERE dj.worker_id = d.worker_id
               )

         GROUP
            BY doa.zip_code
             , n.i
        ) t
  GROUP BY t.zip_code

【讨论】:

以上是关于如何列出各个列,其中每个列包含一个 id 计数,其中每列中的 id 不在 MySQL 中每列的不同表中的主要内容,如果未能解决你的问题,请参考以下文章

mysql查询以获取列中每个元素的计数

如何获取列中每个值的计数?

如何从另一个表中获取每个值的计数?

如何对每个表进行分组计数并按列打印? [复制]

尝试更新包含聚合函数(计数)的选择案例语句时出错

如何列出 CSV 文件中的各个列?