如何在SQL查询中分组并返回特定的行排列?

如何在SQL查询中分组并返回特定的行排列?,sql,permutation,Sql,Permutation,举个例子,这个问题更容易回答 假设表A包含两组A、B、C和D、E、F的两列上的所有排列: **id1** | **id2** A | B A | C B | A B | C C | A C | B D | E D | F E | D E | F F | D F | E 我想对行进行分组,并在SQL中获得唯一的排列: 查询结果 或 第一列中组的常用字母是一项要求确保第一列始终是较低的值。联合删除重

举个例子,这个问题更容易回答

假设表A包含两组A、B、C和D、E、F的两列上的所有排列:

**id1** | **id2**  
A   | B  
A   | C  
B   | A  
B   | C  
C   | A  
C   | B  
D   | E  
D   | F  
E   | D  
E   | F  
F   | D  
F   | E  
我想对行进行分组,并在SQL中获得唯一的排列:

查询结果


第一列中组的常用字母是一项要求

确保第一列始终是较低的值。联合删除重复项:

select id1, id2
from
(
    select id1, id2 from a where id1 <= id2
    union
    select id2, id1 from a where id1 > id2
)
where id1 in ('A', 'D')
执行为:

SQL>select id1, id2
SQL&from
SQL&(
SQL&    select id1, id2 from a where id1 <= id2
SQL&    union
SQL&    select id2, id1 from a where id1 > id2
SQL&)
SQL&where id1 in ('A', 'D');
id1 id2
=== ===
A   B
A   C
D   E
D   F

                  4 rows found

如果我们可以假设Oracle数据库中存在公共表表达式CTE,那么Postgresql和SQL Server都可以使用第一个选项

这假设首先返回ID1最小的集合是可以接受的。如果您想要一个具有最大ID1的,只需更改

如果您想要一个大小不同的中间值。。。那将需要更多的工作

WITH T2 as (SELECT * FROM t WHERE ID1 < ID2)
SELECT * 
FROM t2 
WHERE ID1 not in (Select ID2 FROM t2)
如果不是

SELECT * 
FROM (SELECT * 
      FROM t 
      WHERE ID1 < ID2)
WHERE ID1 not in (SELECT ID2 
                  FROM (SELECT * 
                        FROM t 
                        WHERE ID1 < ID2)A )
虽然您可以使用not exists代替IN。。。但是我很着急

现在,若你们有一个集合数据表和一个集合编号

with T (ID1, SetNo) as (
SELECT 'A',1 from dual UNION ALL
SELECT 'B',1 from dual UNION ALL
SELECT 'C',1 from dual UNION ALL
SELECT 'D',2 from dual UNION ALL
SELECT 'E',2 from dual UNION ALL
SELECT 'F',2 from dual )

SELECT A.ID1, B.ID1 as ID2 
FROM (Select MIN(ID1) ID1, SetNO from t group by SetNo) A
CROSS JOIN T B
WHERE  B.ID1 <> A.ID1 and A.SetNo = B.SetNo

B,C和E,F呢?为什么要将它们排除在外?这背后的实际用例是线串几何体的捕捉。在本例中,当对每一行单独进行捕捉时,B、C和E、F将创建冗余捕捉,或引入错误。您的dbms是什么?因此,启动w/{A、B或C}或{D、E或F}并不重要,只要不存在任何集合的重复?A、B、C和D、E、F是完全独立的,是的。它们是线字符串的不同交点,彼此之间没有任何关系。得到12个结果不是应该是4吗?@xQbert,我得到6行。更好的是,我只是不喜欢硬编码。@xQbert,老实说,我也不喜欢。。。我也得工作!谢谢-这很有效:我不能硬编码值
SELECT * 
FROM (SELECT * 
      FROM t 
      WHERE ID1 < ID2)
WHERE ID1 not in (SELECT ID2 
                  FROM (SELECT * 
                        FROM t 
                        WHERE ID1 < ID2)A )
with T (ID1, SetNo) as (
SELECT 'A',1 from dual UNION ALL
SELECT 'B',1 from dual UNION ALL
SELECT 'C',1 from dual UNION ALL
SELECT 'D',2 from dual UNION ALL
SELECT 'E',2 from dual UNION ALL
SELECT 'F',2 from dual )

SELECT A.ID1, B.ID1 as ID2 
FROM (Select MIN(ID1) ID1, SetNO from t group by SetNo) A
CROSS JOIN T B
WHERE  B.ID1 <> A.ID1 and A.SetNo = B.SetNo