从每个类别中至少选择一个,但不能超过一个,并且不能与另一列重复
Posted
技术标签:
【中文标题】从每个类别中至少选择一个,但不能超过一个,并且不能与另一列重复【英文标题】:Select at least one from each category but no more than one, and no duplicates of another column 【发布时间】:2016-12-09 03:54:26 【问题描述】:给定如下表格:
Id | Vehicle Type | Manufacturer
--------------------------------
1 | Car | SpaceCo
2 | Car | NeatCarsInc
3 | Car | NeatCarsInc
4 | Spaceship | SpaceCo
5 | Spaceship | NeatCarsInc
6 | Spaceship | SpaceCo
7 | Boat | WeMakeBoats
8 | Boat | SpaceCo
9 | Boat | NeatCarsInc
我需要能够编写查询以满足以下条件:
要求 #1 确保给定的车辆类型不会在结果集中重复 要求 #2 确保给定的制造商不会在结果集中重复 Req #3 如果有任何车辆类型的条目,那么每个车辆类型都应该有一个输出行(在 Req #1 和 Req #2 的约束内) 注意:每个制造商在结果集中可以出现 0-1 次,不需要尝试选择每个制造商我并不特别关心返回哪个 Id(例如,最小 Id 就足够了)。
一个有效的结果集可能是:
1 | Car | SpaceCo
5 | Spaceship | NeatCarsInc
7 | Boat | WeMakeBoats
这同样可以接受:
2 | Car | NeatCarsInc
4 | Spaceship | SpaceCo
7 | Boat | WeMakeBoats
但是,理想情况下,这不是可以接受的(因为它为 Car Vehicle Type 遗漏了一行,从而违反了 Req #3):
9 | Boat | NeatCarsInc
6 | Spaceship | SpaceCo
重要的是车辆类型或制造商列都没有重复,并且如果可能,为每个车辆类型选择一个条目。
请注意,这与以下问题相似但不同:Select at least one from each category?,因为我们 (1) 使用两个类别,并且 (2) 不允许任何一个类别的重复条目。
尝试的方法
回想一下,我不确定这在 SQL 中是否可行,因为这听起来很接近背包问题...
我能得到的最接近的是:
-
对车辆类型进行排名,为每种车辆类型选择第一个条目
将此集合排在制造商之上,为每个制造商选择第一个条目
这要求我违反 Req #3,即根据所使用的排名顺序,它可能会产生以下任何结果:
按 ID 升序排序:
1 | Car | SpaceCo
7 | Boat | WeMakeBoats
按 Id 降序排列:
6 | Spaceship | SpaceCo
9 | Boat | NeatCarsInc
按随机 ID 排序(可能性):
2 | Car | NeatCarsInc
6 | Spaceship | SpaceCo
7 | Boat | WeMakeBoats
示例 SQL 如下:
SELECT Id, VehicleType, Manufacturer
FROM
(
SELECT
RANK() OVER (PARTITION BY Manufacturer ORDER BY [Id] ASC) ManufacturerRank,
Id,
VehicleType,
Manufacturer
FROM
(
SELECT
RANK() OVER (PARTITION BY VehicleType ORDER BY [Id] ASC) VehicleRank,
Id,
VehicleType,
Manufacturer
FROM
Vehicles
) RankedPerVehicleType
WHERE VehicleRank = 1
) RankedPerManufacturer
WHERE ManufacturerRank = 1
【问题讨论】:
每个集合都依赖于另一个。我不认为它可以在 just SQL 中完成。我认为您需要以程序方式进行。 这种方法怎么样 1.首先选择所有不同的车辆类型 --say 表 1 2.选择所有不同的制造商 -say 表 2 2.在过程或函数中,遍历表 1 的每一行 3 . 对于第一行,从 table2 中选择任何随机数 4. 对于其他行,选择任何随机数,但不是在前一行中使用的 @MattMitchel 为什么你还要像这样存储数据?我的意思是Id
2
和 3
有相同的数据。
@JibinBalachandran - 假设它们是单独的车辆,并且 Id 2 和 Id 3 还有另一个(不相关的)RegistrationPlateNumber 字段。
@GurwinderSingh - 我认为你是对的
【参考方案1】:
如果你不介意ID,你可以给一个方法
CREATE TABLE #TAB (Id INT, Vehicle_Type VARCHAR(250), Manufacturer VARCHAR(250))
INSERT INTO #TAB
SELECT 1,'Car','SpaceCo'
UNION ALL
SELECT 2,'Car','NeatCarsInc'
UNION ALL
SELECT 3,'Car','NeatCarsInc'
UNION ALL
SELECT 4,'Spaceship','SpaceCo'
UNION ALL
SELECT 5,'Spaceship','NeatCarsInc'
UNION ALL
SELECT 6,'Spaceship','SpaceCo'
UNION ALL
SELECT 7,'Boat','WeMakeBoats'
UNION ALL
SELECT 8,'Boat','SpaceCo'
UNION ALL
SELECT 9,'Boat','NeatCarsInc'
SELECT Vehicle_Type,Manufacturer
FROM (
SELECT DISTINCT DENSE_RANK() OVER ( ORDER BY Vehicle_Type) AS SNO, Vehicle_Type FROM #TAB
)VT
INNER JOIN (
SELECT DISTINCT DENSE_RANK() OVER ( ORDER BY Manufacturer) AS SNO, Manufacturer FROM #TAB
)MF
ON VT.SNO= MF.SNO
结果会是
+--------------+--------------+
| Vehicle_Type | Manufacturer |
+--------------+--------------+
| Boat | NeatCarsInc |
| Car | SpaceCo |
| Spaceship | WeMakeBoats |
+--------------+--------------+
【讨论】:
添加新行:10,plane ,NeatCarsInc 并重试。它会失败 亲爱的@GurwinderSingh OP 提到Each Manufacturer can appear 0-1 times in the result set, and there is no requirement to try to select every Manufacturer.
请阅读问题
@ShakeerMirza - 这不适用于不同的数据。例如,从 NeatCarsInc 输入所有 3 辆汽车,您的代码仍将返回 SpaceCo 作为汽车制造商。【参考方案2】:
SELECT DISTINCT Id, VehicleType, Manufacturer
FROM
(
SELECT
RANK() OVER (PARTITION BY Manufacturer ORDER BY [Id] ASC) ManufacturerRank,
Id,
VehicleType,
Manufacturer
FROM
(
SELECT
RANK() OVER (PARTITION BY VehicleType ORDER BY [Id] ASC) VehicleRank,
Id,
VehicleType,
Manufacturer
FROM
Vehicles
) RankedPerVehicleType
WHERE VehicleRank = 1
) RankedPerManufacturer
WHERE ManufacturerRank = 1
【讨论】:
移到 Select 之后。否则会给出语法错误\ 我不确定这会增加什么?这是我与 Distinct 添加共享的示例方法,它没有解决示例方法的任何挑战。【参考方案3】:由于您似乎并不关心 id,因此可以解决问题:
select distinct [Vehicle Type] into #1 from table_1
select distinct [Manufacturer] into #2 from table_1
select * from #1 cross join #2
drop table #1
drop table #2
【讨论】:
以上是关于从每个类别中至少选择一个,但不能超过一个,并且不能与另一列重复的主要内容,如果未能解决你的问题,请参考以下文章
Hibernate Query 将映射实体集合与给定集合中的至少一个元素匹配,并且不能在另一个多对多关系中匹配