如何构造SQL查询以防止返回包含相关数据的重复行?

时间:2019-01-28 15:39:28

标签: sql sql-server

我需要一些有关SQL查询的帮助。我有一个数据库表,该表具有与其他表相关的数据。当我查询表格时,它会为相关数据的每一行返回重复的行,即

|-------------|           |-------------|           |-------------|
| Cars        |           | Options     |           | Value       |
|-------------|  ------>  |-------------|  ------>  |-------------|
| CarId       |           | OptionsId   |           | ValueId     |
| CarMake     |           | OptionName  |           | CostValue   |
| CarModel    |           | Confirmed   |           | CarId       |
|-------------|           | CarId       |           | OptionsId   |
                          |-------------|           |-------------|
        |
        |
        --------------->  |-------------|
                          | Warranty    |
                          |-------------|
                          | WarrantyId  |
                          | WarrantyType|
                          | CarId       |
                          |-------------|

我所做的查询是在SSMS的查询生成器中设计的(因为它不使用别名并且具有3阶段命名约定,因此将被更改)如下:

SELECT dbo.Cars.CarId, 
       dbo.Cars.Make, 
       dbo.Cars.Model, 
       dbo.Options.OptionName, 
       dbo.Warranty.WarrantyType,
       dbo.Value.CostValue
FROM   dbo.Cars 
       LEFT JOIN dbo.Options ON dbo.Cars.CarId = dbo.Options.CarId 
       LEFT JOIN Value ON Options.OptionsId = Value.OptionsId 
       LEFT JOIN dbo.Warranty on dbo.Cars.CarId = dbo.Warranty.CarId

直接执行此查询会返回我的数据,但是,对于具有多个选项的汽车,我会收到重复的行,即

Id | Make | Model  | Option Name      | Warranty Type | Value  
27 | Ford | Fiesta | Heated Seats     | Static        | 500
27 | Ford | Fiesta | Front Fog Lights | Static        | 400

我一直在寻找这个问题的可能答案,发现建议的解决方案是使用关键字DISTINCT或创建一个子查询。我在查询中添加了DISTINCT,但返回了相同的数据,可能是因为选项本身是不同的,我不知道我在猜测什么。

我很高兴使用子查询,但是不确定如何将其应用于我上面的查询代码。我在这里要做的就是为每辆车返回最高选择值的单行。

27 | Ford | Fiesta | Heated Seats  |  Static  | 500

有人可以帮我写这个查询吗?我想我已经把这个问题包括在内了,但是如果我能提供更多,请告诉我。

2 个答案:

答案 0 :(得分:1)

而不是联接提供多行的表Value
您必须加入此查询:

SELECT 
  dbo.Value.CarId, 
  dbo.Value.OptionsId, 
  MAX(dbo.Value.CostValue) AS CostValue
FROM dbo.Value
GROUP BY dbo.Value.CarId, dbo.Value.OptionsId 

您将从表Value中为每辆车选择最大价值的选项。
所以试试这个:

SELECT dbo.Cars.CarId, 
       dbo.Cars.Make, 
       dbo.Cars.Model, 
       dbo.Options.OptionName, 
       v.CostValue,
       dbo.Warranty.WarrantyType
FROM   dbo.Cars 
       LEFT JOIN dbo.Options ON dbo.Cars.CarId = dbo.Options.CarId 
       INNER JOIN (
                  SELECT 
                  dbo.Value.CarId, 
                  dbo.Value.OptionsId, 
                  MAX(dbo.Value.CostValue) AS CostValue
                  FROM dbo.Value
                  GROUP BY dbo.Value.CarId, dbo.Value.OptionsId  
       ) AS v ON Options.OptionsId = v.OptionsId 
       LEFT JOIN dbo.Warranty on dbo.Cars.CarId = dbo.Warranty.CarId

答案 1 :(得分:0)

您可以使用窗口功能尝试以下操作

 with cte as(
           SELECT    dbo.Cars.CarId, 
           dbo.Cars.Make, 
           dbo.Cars.Model, 
           dbo.Options.OptionName, 
           Value.CostValue,
           row_number() over(partition by dbo.Cars.CarId, 
           dbo.Cars.Make, 
           dbo.Cars.Model order by Value.CostValue desc) rn   
    FROM   dbo.Cars 
           LEFT JOIN dbo.Options ON dbo.Cars.CarId = dbo.Options.CarId 
           LEFT JOIN Value ON Options.OptionsId = Value.OptionsId 
           LEFT JOIN dbo.Warranty on dbo.Cars.CarId = dbo.Warranty.CarId
          ) select * from cte where rn=1