我尝试编写查询以查找特定字段中的不同值,计算该值的出现次数,对于该特定值的所有实例,满足另一列值,然后将结果显示为如下(更多解释如下):
示例db:
RowId Status MemberIdentifier
----- ------ ----------------
1 In Progress 111111111
2 Complete 123456789
3 Not Started 146782452
4 Complete 111111111
5 Complete 123456789
6 Not Started 146782452
7 Complete 111111111
期望的结果:
Status MemberIdentifierCount
------ ----------------------
Not Started 1
In Progress 1
Complete 1
在上面的查询中,计算并显示具有给定状态的不同MemberIdentifier的数量。如果MemberIdentifier有两行Status' Complete'但有一个状态正在进行中,'它被分组并计入进行中(即,MemberIdentifier = 111111111)。要将MemberIdentifier分组并计为完成,其所有行的状态必须为“完成”状态。 (即,MemberIdentifier = 123456789)。任何见解都将受到赞赏(MySQL新手)。
答案 0 :(得分:10)
每个MemberIdentifier找到您认为合适的状态,例如'In Progress'
胜过'Complete'
和'Not Started'
。 'Not Started'
胜过'Complete'
。为此使用条件聚合。
select status, count(*)
from
(
select
case when sum(status = 'In Progress') > 0 then 'In Progress'
when sum(status = 'Not Started') > 0 then 'Not Started'
else 'Complete'
end as status
from mytable
group by memberidentifier
) statuses
group by status;
答案 1 :(得分:6)
SELECT max_status AS Status
, COUNT(*) AS ct
FROM (
SELECT MAX(Status) AS max_status
FROM tbl
GROUP BY MemberIdentifier
) AS a
GROUP BY max_status;
这利用了这些字符串的比较方式:“进行中”> “完成”。在这样做时,它会对具有多个状态的任何其他成员执行随机操作。
答案 2 :(得分:5)
<强> SQL 强>
SELECT AdjustedStatus AS Status,
COUNT(*) AS MemberIdentifierCount
FROM
(SELECT IF(Status='Complete',
IF(EXISTS(SELECT Status
FROM tbl t2
WHERE t2.Status = 'In Progress'
AND t2.MemberIdentifier = t1.MemberIdentifier),
'In Progress',
'Complete'),
Status) AS AdjustedStatus,
MemberIdentifier
FROM tbl t1
GROUP BY AdjustedStatus, MemberIdentifier) subq
GROUP BY AdjustedStatus;
在线演示
<强>解释强>
第一个IF()
function检查状态是否为“完成”,如果是,则检查是否存在具有相同MemberIdentifier
但状态为“正在进行”的另一个记录:这样做通过IF(EXISTS(SELECT...)))
。如果找到,则会将“正在进行”状态分配给AdjustedStatus
字段,否则AdjustedStatus
将根据(未经调整的)Status
值进行设置。
对于表格中的每一行,GROUP BY
AdjustedStatus
和MemberIdentifier
已经调整后的状态是这样得出的,以获得这两个字段值的所有唯一组合。然后将其制作为子查询 - 别名为subq
。然后汇总(GROUP BY
)AdjustedStatus
并计算出现次数,即每次出现的唯一MemberIdentifier
次数。
答案 3 :(得分:5)
我假设您有2个表格如下
CREATE TABLE table1 (RowId INT PRIMARY KEY, MemberIdentifier VARCHAR(255));
INSERT INTO table1 (RowId, MemberIdentifier)
VALUES
(1,'111111111'), (2, '123456789'), (3, '146782452'), (4, '111111111'),(5,'123456789'), (6,'146782452'), (7,'111111111');
CREATE TABLE table2 (RowId INT PRIMARY KEY, Status VARCHAR(255));
INSERT INTO table2 (RowId, Status)
VALUES
(1,'In Progress'), (2,'Complete' ), (3,'Not Started'), (4,'Complete' ), (5,'Complete' ), (6,'Not Started'), (7,'Complete' );
假设您在这些表格中没有数百万条记录,您可以使用下面的查询来实现您想要的效果。
SELECT CASE WHEN not_started.Status = 'Not Started'
THEN 'Not Started'
WHEN in_progress.Status = 'In Progress'
THEN 'In Progress'
WHEN complete.Status = 'Complete'
THEN 'Complete'
END AS over_all_status,
COUNT(*) AS MemberIdentifierCount
FROM (SELECT DISTINCT t1.MemberIdentifier
FROM table1 t1) main
LEFT OUTER JOIN
(SELECT DISTINCT t1.MemberIdentifier, t2.Status
FROM table1 t1,
table2 t2
WHERE t1.RowId = t2.RowId
AND t2.Status = 'In Progress') in_progress
ON (main.MemberIdentifier = in_progress.MemberIdentifier)
LEFT OUTER JOIN
(SELECT DISTINCT t1.MemberIdentifier, t2.Status
FROM table1 t1,
table2 t2
WHERE t1.RowId = t2.RowId
AND t2.Status = 'Not Started') not_started
ON (main.MemberIdentifier = not_started.MemberIdentifier)
LEFT OUTER JOIN
(SELECT DISTINCT t1.MemberIdentifier, t2.Status
FROM table1 t1,
table2 t2
WHERE t1.RowId = t2.RowId
AND t2.Status = 'Complete') complete
ON (main.MemberIdentifier = complete.MemberIdentifier)
GROUP BY over_all_status;
基本上,查询为每个MemberIdentifier创建一条记录,其中包含所有可能的三种状态。然后,它根据总体状态对结果进行分组并输出计数。
查询的输出是
答案 4 :(得分:3)
select MemberIdentifier
,case
when total = cn then 'Complete'
when total < cn then 'In Progress'
when total is null then 'Not Started' END as Fstatus
from
(
select sum(stat) total,MemberIdentifier,(select count(MemberIdentifier) as cnt from tbldata t1
where t1.MemberIdentifier = C.MemberIdentifier
group by MemberIdentifier) as cn
from (
select MemberIdentifier,case status when 'In Progress' then -1
when 'Complete' Then 1
when 'Not Started' then null End as Stat from tbldata
) C
group by MemberIdentifier
) as f1
Select count(fstatus) counts,fstatus from (
select MemberIdentifier
,case when total = cn then 'Complete'
when total < cn then 'In Progress'
when total is null then 'Not Started' END as Fstatus
from
(
select sum(stat) total,MemberIdentifier,(select count(MemberIdentifier) as cnt from tbldata t1
where t1.MemberIdentifier = C.MemberIdentifier
group by MemberIdentifier) as cn
from (
select MemberIdentifier
,case status when 'In Progress' then -1 when 'Complete' Then 1 when 'Not Started' then null End as Stat from tbldata
) C
group by MemberIdentifier
) as f1
) f2 group by fstatus
输出:
counts fstatus
1 Complete
1 In Progress
1 Not Started
答案 5 :(得分:2)
如果status
的优先顺序是
Not Started
In Progress
Complete
我们可以使用快捷方式......
SELECT t.memberIdentifier
, MAX(t.status) AS status
FROM mytable t
GROUP BY t.MemberIdentifier
这使我们得到了独特的memberIdentifier
。
如果某个成员的行有'In Progress'
和'Complete'
状态,则查询将返回'In Progress'
作为状态。
如果该成员的不有任何状态大于'Complete'
的行,我们将为成员返回状态'Complete'
。
要从该结果中获取计数,我们可以将该查询引用为内联视图:
SELECT q.status
, COUNT(q.memberIdentifier)
FROM (
SELECT t.memberIdentifier
, MAX(t.status) AS status
FROM mytable t
GROUP BY t.MemberIdentifier
) q
ORDER BY q.status
想想是否这样...... MySQL首先在parens之间运行查询(MySQL称之为&#34;派生表&#34;。查询的结果是一组行,可以像查询一样查询表
我们可以做COUNT(DISTINCT q.memberIdentifier)
或假设memberIdentifier保证非NULL,我们可以COUNT(1)
或SUM(1)
获得相同的结果。 (内联视图中的GROUP BY保证memberIdentifier将是唯一的。)
在更一般的情况下,我们没有方便的状态优先顺序的字母排序快捷方式......我们可以使用一个表达式返回&#34;顺序&#34; ;。这使查询更复杂,但它的工作方式相同。
我们可以用以下内容替换t.status
:
CASE t.status
WHEN 'Complete' THEN 1
WHEN 'In Progress' THEN 2
WHEN 'Not Started' THEN 3
ELSE 4
END AS `status_priority`
用反向替换q.status
,转换回字符串:
CASE q.status_priority
WHEN 1 THEN 'Complete'
WHEN 2 THEN 'In Progress'
WHEN 3 THEN 'Not Started'
ELSE NULL
END AS `status`
我们需要决定如何处理状态值,这些值不是三个中的一个......是否会被忽略,处理的优先级高于其他任何一个。 (测试用例包含status = 'Unknown'
行和status = 'Abracadabra
行。
答案 6 :(得分:2)
我刚刚修改@ thorsten-kettner的解决方案,因为你在加入桌子时遇到了问题。我假设你有2个表,table1 - 至少有2行(RowID和MemberIdentifier)和table2 - 至少有2行(RowID和Status)
select Status, count(*)
from(
select
case when sum(newTable.Status = 'In Progress') > 0 then 'In Progress'
when sum(newTable.Status = 'Not Started') > 0 then 'Not Started'
else 'Complete'
end as status
from (
select table1.RowId as RowId, table1.MemberIdentifier as MemberIdentifier, table2.Status as Status from table1 INNER JOIN table2 ON table1.RowId = table2.RowId
)newTable
group by newTable.MemberIdentifier
) statuses
group by Status;
答案 7 :(得分:1)
使用特定表配置顺序的另一种方法(映射到两个整数的幂)。
此映射允许bit_or
聚合简单地转置数据。
http://rextester.com/edit/ZSG98543
-- Table bit_progression to determine priority
CREATE TABLE bit_progression (bit_status int PRIMARY KEY, Status VARCHAR(255));
INSERT INTO bit_progression (bit_status, Status)
VALUES
(1, 'Not Started'),
(2, 'Complete' ),
(4, 'In Progress');
select
Status,
count(*)
from
(
select
MemberIdentifier,max(bit_status) bit_status
from
tbl natural join bit_progression
group by
MemberIdentifier
) Maxi natural join bit_progression
group by
Status
;
生产
Status count(*)
1 Complete 1
2 In Progress 1
3 Not Started 1
额外:
select
MemberIdentifier,
bit_or(bit_status) bits_status,
case when bit_or(bit_status) & 4 = 4 then true end as withStatusInProgress,
case when bit_or(bit_status) & 2 = 2 then true end as withStatusComplete,
case when bit_or(bit_status) & 1 = 1 then true end as withStatusNotStarted
from
tbl natural join bit_progression
group by
MemberIdentifier
;
制作它:
MemberIdentifier bits_status withStatusInProgress withStatusComplete withStatusNotStarted
111111111 6 1 1 NULL
123456789 2 NULL 1 NULL
146782452 1 NULL NULL 1