从每个类别中至少选择一个,但不能超过一个,并且不能与另一列重复

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 23 有相同的数据。 @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

【讨论】:

以上是关于从每个类别中至少选择一个,但不能超过一个,并且不能与另一列重复的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的模型查询集不能正常工作?

MYSQL 从每个类别中选择一个随机记录

bzoj3087: Coci2009 misolovke

Hibernate Query 将映射实体集合与给定集合中的至少一个元素匹配,并且不能在另一个多对多关系中匹配

强制每个 Keras 批次包含每个类别中的至少一个图像是不好的做法吗?

将数据拆分为训练/测试文件,以便为两个文件选择至少一个样本