连续数分组的SQL查询
假设我有下表:连续数分组的SQL查询,sql,sql-server,tsql,group-by,Sql,Sql Server,Tsql,Group By,假设我有下表: | ... | orderId | serialNumber | type | ... | |-----|---------|--------------|---------------|-----| | ... | 1 | 01 | someType | ... | | ... | 1 | 02 | someType | ... | | ... | 1 | 03
| ... | orderId | serialNumber | type | ... |
|-----|---------|--------------|---------------|-----|
| ... | 1 | 01 | someType | ... |
| ... | 1 | 02 | someType | ... |
| ... | 1 | 03 | someOtherType | ... |
| ... | 1 | 04 | someOtherType | ... |
| ... | 1 | 05 | someType | ... |
| ... | 1 | 06 | someType | ... |
| ... | 2 | 07 | someType | ... |
| ... | 2 | 08 | someType | ... |
我希望我的查询生成以下结果:
| orderId | count | min | max | type |
|---------|-------|-----|-----|---------------|
| 1 | 2 | 01 | 02 | someType |
| 1 | 2 | 03 | 04 | someOtherType |
| 1 | 2 | 05 | 06 | someType |
| 2 | 4 | 07 | 08 | someType |
我需要按类型和医嘱ID分组。当serialNumber未运行时,应创建一个新条目
这是我当前的查询:
SELECT
orderId,
count(*) AS count,
min(serialNumber) AS min,
max(serialNumber) AS max,
type
FROM tblMyTable
group by type, orderId
order by orderId
但它造成的结果是错误的:
| orderId | count | min | max | type |
|---------|-------|-----|-----|---------------|
| 1 | 4 | 01 | 06 | someType | <-- this should be 2 entries
| 1 | 2 | 03 | 04 | someOtherType |
| 2 | 2 | 07 | 08 | someType |
这可能需要一些运行,但只是一个开始
with cte as (
SELECT *, row_number() over (partition by type, orderId order by serialNumber) as rn
FROM Table1
)
SELECT *
FROM cte c1
LEFT JOIN cte c2
ON c1.orderId = c2.orderId
AND c1.type = c2.type
AND c1.rn = c2.rn-1
AND c1.rn % 2 = 1
输出
+----+---------+--------------+---------------+----+---------+--------------+---------------+------+
| | orderId | serialNumber | type | rn | orderId | serialNumber | type | rn |
+----+---------+--------------+---------------+----+---------+--------------+---------------+------+
| 1 | 1 | 3 | someOtherType | 1 | 1 | 4 | someOtherType | 2 |
| 2 | 1 | 4 | someOtherType | 2 | NULL | NULL | NULL | NULL |
| 3 | 1 | 1 | someType | 1 | 1 | 2 | someType | 2 |
| 4 | 1 | 2 | someType | 2 | NULL | NULL | NULL | NULL |
| 5 | 1 | 5 | someType | 3 | 1 | 6 | someType | 4 |
| 6 | 1 | 6 | someType | 4 | NULL | NULL | NULL | NULL |
| 7 | 2 | 7 | someType | 1 | 2 | 8 | someType | 2 |
| 8 | 2 | 8 | someType | 2 | NULL | NULL | NULL | NULL |
+----+---------+--------------+---------------+----+---------+--------------+---------------+------+
这里还有另一个选项,假设序列由
[serialNumber]
决定
这通常称为缺口和孤岛问题
示例
;with cte as (
Select *
,Grp = sum(Flg) over (order by [serialNumber])
From (
Select *
,Flg = case when concat(orderid,type)<> lag(concat(orderid,type),1) over (Order by [serialNumber]) then 1 else 0 end
From YourTable
) A
)
Select [orderid]
,[count] = count(*)
,[min] = min ([serialNumber])
,[max] = max ([serialNumber])
,[type] = max([type])
From cte
Group by [orderid],Grp
这是一个缺口和孤岛问题,但我会使用行号差异的方法:
select orderid, count(*), min(serialNumber), max(serialNumber), type
from (select t.*,
row_number() over (partition by orderid order by serialnumber) as seqnum,
row_number() over (partition by orderid, type order by serialnumber) as seqnum_type
from t
) t
group by orderid, type, (seqnum - seqnum_type)
order by orderid, min(serialNumber);
您的serialnumber
看起来像一个字符串,但它有数值。如果您可以信任它的顺序,您甚至不需要两个行号值:
select orderid, count(*), min(serialNumber), max(serialNumber), type
from (select t.*,
row_number() over (partition by orderid, type order by serialnumber) as seqnum_type
from t
) t
group by orderid, type, (serialnumber - seqnum_type)
order by orderid, min(serialNumber);
这样做的原因有点难以解释,但如果您运行子查询,这是很明显的。您将看到行号之间的差异如何标识您想要标识的组。我猜您对SQL分组的解释有点错误。分组是不考虑记录顺序的。它聚合了所有具有相同分组字段值的记录(在您的案例中是orderId和type)。要将一行拆分为两行,您应该找到一些使这行不同的字段。您的rdbms是什么?Sql Server、postgres、oracle?MS Transact-Sqlall类型成对出现?不,也可以出现单个类型。我已经用这些信息更新了我的问题。更干净了。。。我刚把旗子的方法卡在我的小脑袋里+1
select orderid, count(*), min(serialNumber), max(serialNumber), type
from (select t.*,
row_number() over (partition by orderid order by serialnumber) as seqnum,
row_number() over (partition by orderid, type order by serialnumber) as seqnum_type
from t
) t
group by orderid, type, (seqnum - seqnum_type)
order by orderid, min(serialNumber);
select orderid, count(*), min(serialNumber), max(serialNumber), type
from (select t.*,
row_number() over (partition by orderid, type order by serialnumber) as seqnum_type
from t
) t
group by orderid, type, (serialnumber - seqnum_type)
order by orderid, min(serialNumber);