1

如果我有以下数据,其中一个规则可以有多个条件:

-------------------
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

谢谢你的帮助。

4

4 回答 4

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;
于 2013-05-15T22:03:42.313 回答
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
于 2013-05-15T22:11:26.717 回答
1

我的使用SQL Server 的LISTAGG/GROUP_CONCAT仿真

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

于 2013-05-15T22:19:55.400 回答
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
于 2013-05-15T22:00:25.807 回答