如果我有以下数据,其中一条规则可以有多个条件:
-------------------
RuleId CriteriaId
-------------------
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
如何在对规则的所有条件进行分组时获得最小 RuleId。换句话说,由于规则1和规则2具有完全相同的标准,因此它们将位于一个组中,但由于规则3不具有相同的标准,因此它将位于不同的组中。
我希望得到以下结果:
-------------------
RuleId CriteriaId
-------------------
1 1
1 2
1 3
3 1
3 2
在RuleId上使用MIN进行直接的GROUP BY在这里不起作用,因为这样可以反过来:
-------------------
RuleId CriteriaId
-------------------
1 1
1 2
1 3
感谢您的帮助。
答案 0 :(得分:1)
示例数据
create table rules (RuleId int, CriteriaId int);
insert into rules values
(1 ,1),
(1 ,2),
(1 ,3),
(2 ,1),
(2 ,2),
(2 ,3),
(3 ,1),
(3 ,2);
您的查询
;with flattened as (
select r.ruleid, (select ',' + rtrim(r2.criteriaid)
from rules r2
where r2.RuleId = r.RuleId
order by r2.criteriaid
for xml path(''), type).value('/','varchar(max)') list
from rules r
group by r.ruleid
)
select r3.*
from rules r3
join (
select min(ruleid) min_ruleid
from flattened
group by list) r4 on r4.min_ruleid = r3.ruleid
order by r3.ruleid, r3.CriteriaId;
答案 1 :(得分:1)
我不确定这是绝对最好的方法,但它有效。
CREATE TABLE GroupingTest (RuleId int, CriteriaId int)
INSERT INTO GroupingTest VALUES
(1, 1),
(1, 2),
(1, 3),
(2, 1),
(2, 2),
(2, 3),
(3, 1),
(3, 2)
----------------------------------------------------
WITH MergedGroupingCriteria AS (
SELECT DISTINCT RuleId,
STUFF((SELECT ', ' + CAST(CriteriaId AS varchar)
FROM GroupingTest GT
WHERE GT.RuleId = MergeGroup.RuleId
FOR XML PATH(''),TYPE).value('.','VARCHAR(MAX)')
, 1, 2, '') AS MergedGrouping
FROM GroupingTest MergeGroup )
SELECT MIN(GroupingTest.RuleId), GroupingTest.CriteriaId
FROM GroupingTest
JOIN MergedGroupingCriteria
ON GroupingTest.RuleId = MergedGroupingCriteria.RuleId
GROUP BY MergedGroupingCriteria.MergedGrouping, GroupingTest.CriteriaId
ORDER BY MIN(GroupingTest.RuleId), GroupingTest.CriteriaId
答案 2 :(得分:1)
我的使用SQL Server's LISTAGG
/GROUP_CONCAT
emulation:
SELECT MIN(list.ruleid) minrule, rules
FROM
(SELECT RuleId,
stuff((
SELECT ', ' + CriteriaId
FROM Table1 as t1
where t1.RuleId = t2.RuleId
FOR XML PATH('')
), 1, 2, '') Rules
FROM Table1 as t2
GROUP BY RuleId) list
GROUP BY Rules
ORDER BY minrule;
这是 SQL Fiddle 。
我假设两个字段都为varchar
,我的结果仍然连接在一起。
修改强>
以下查询没有假设,并提供了正确的结果格式:
SELECT *
FROM Table1
WHERE RuleId IN
(SELECT MIN(list.ruleid) minrule
FROM
(SELECT RuleId,
stuff((
SELECT ', ' + CAST(CriteriaId AS varchar)
FROM Table1 as t1
where t1.RuleId = t2.RuleId
FOR XML PATH('')
), 1, 2, '') Rules
FROM Table1 as t2
GROUP BY RuleId) list
GROUP BY Rules)
ORDER BY RuleId
;
更新了 SQL Fiddle
答案 3 :(得分:0)
这是一种方法。首先,创建一个具有完全匹配条件的所有规则对的列表。如果每条规则上的数字相同,则标准匹配。并且,当我们计算匹配的数量时,匹配的数量与总数相同。
以下查询找到这些对:
select driver.ruleid1, driver.ruleid2
from (select rc1.ruleid as ruleid1, rc2.ruleid as ruleid2,
rc1.numCriteria as Num1, rc2.numCriteria as Num2
from (select ruleid, COUNT(*) as numCriteria from rc group by ruleid) rc1 join
(select ruleid, COUNT(*) as numCriteria from rc group by ruleid) rc2
on rc1.ruleid <= rc2.ruleid and
rc1.numCriteria = rc2.numCriteria
) driver left outer join
rc rc1
on driver.ruleid1 = rc1.ruleid left outer join
rc rc2
on rc2.ruleid = driver.ruleid2 and
rc1.criteriaId = rc2.criteriaid
group by driver.ruleid1, driver.ruleid2
having max(driver.Num1) = COUNT(distinct rc1.ruleid) and
MAX(driver.Num1) = COUNT(distinct rc2.ruleId)
driver
子查询执行第一次传递,使所有规则对具有相同数量的条件。然后加入标准。我意识到这创造了一个小笛卡尔积。但是,要计算条件数,查询将使用count(distinct)
。
要分配唯一的组ID,只需使用rule1的最小值即可。像这样:
with pairs as (
<above subquery>
)
select ruleid2, min(ruleid1) as groupnum
from pairs
group by ruleid2