从每个类别中选择至少一个但不超过一个,并且没有其他列的重复

时间:2016-12-09 03:54:26

标签: sql sql-server

给出如下表格:

 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 确保结果集中不重复给定的车辆类型
  • Req#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  

然而,这理想情况下是可以接受的(因为它为汽车类型遗漏了一行,从而违反了第3号请求):

9  | Boat         | NeatCarsInc
6  | Spaceship    | SpaceCo   

重要的是既不车辆类型或制造商列有任何重复,并且如果可能,为每种车辆类型选择一个条目。

请注意,这与此问题类似但不同:Select at least one from each category?因为我们(1)使用两个类别,(2)不允许任何类别的重复条目。

尝试方法

反思,我不确定这在SQL中是否可行,因为它听起来非常接近背包问题......

我能得到的最接近的是:

  1. 排名车型,选择每种车型的第一个条目
  2. 将此设置排在制造商之上,选择每个制造商的第一个条目
  3. 这要求我违反 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
    

3 个答案:

答案 0 :(得分:0)

如果您对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  |
+--------------+--------------+

答案 1 :(得分:0)

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

答案 2 :(得分:0)

由于您似乎并不关心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