如何列出各个列,其中每个列包含一个 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 by 和 columns由查询返回。 如果您编辑问题并添加所涉及表的架构,则可以完成更具体的答案。为了创建正确的查询,了解某些列的类型很重要。 另外,我怀疑 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 中每列的不同表中的主要内容,如果未能解决你的问题,请参考以下文章