MIN()具有一些标准的聚合函数

时间:2014-09-11 09:10:30

标签: sql-server tsql sql-server-2012

我的表Places包含以下列:

PlaceId     CityId     Name       Postcode
-----------------------------------------
1           1          Place1     NULL
2           1          Place1     10000
3           2          Place1     10300
4           2          Place2     10500
5           3          Place3     NULL
6           3          Place3     NULL

我想要的输出是:

PlaceId     CityId     Name       Postcode
-----------------------------------------
2           1          Place1     10000
3           2          Place1     10300
4           2          Place2     10500
5           3          Place3     NULL

所以,我需要关注:

如果一个城市的CityIdName列重复,那么我需要一行最小PlaceId。但是,如果两个重复项中的第一个在Postcode列中具有NULL,并且较大的id在同一列中具有某个值,那么我需要输出中的第二行(例如,具有ID 1和2的行,返回具有id 2的行) 。如果所有重复项在Postcode列中都具有NULL值,则只返回最小PlaceId(例如,带有id 5和6的行,返回的行带有id 5)

因此,列Postcode影响最终输出

我试过这样的事:

SELECT 
        MIN(nm.PlaceId) AS PlaceId,
        nm.CityId,
        nm.name,        
        COUNT(*) AS Number
    FROM dbo.Place AS nm
    GROUP BY
        nm.CityId ,
        nm.name

我可以解决这个问题,但解决方案并不好,我要求一些漂亮而优雅的解决方案。

2 个答案:

答案 0 :(得分:1)

以下查询对您有所帮助:

;WITH Places as 
(
    select 1 as PlaceId, 1 as CityId, 'Place1' as Name, NULL as Postcode
    UNION ALL 
    select 2, 1, 'Place1', 10000
    UNION ALL 
    select 3, 2, 'Place1', 10300
    UNION ALL 
    select 4, 2, 'Place2', 10300
    UNION ALL 
    select 5, 3, 'Place3', NULL
    UNION ALL 
    select 6, 3, 'Place3', NULL
)
SELECT t2.PlaceId, groups.CityId, groups.Name, t2.Postcode FROM (
    select CityId, Name from Places GROUP BY CityId, Name
    ) groups 
    CROSS APPLY  
    (
        SELECT TOP(1) 
          d2.PlaceId, d2.Postcode, 
          CASE WHEN d2.Postcode IS NOT NULL THEN 1 ELSE 2 END AS RecordPriority 
        FROM Places d2 
        WHERE d2.CityId = groups.CityId AND d2.Name = groups.Name 
        ORDER BY RecordPriority, PlaceId
    ) t2 ;

或使用与上述ROW_NUMBER()相同的ORDER BY

;WITH Places AS 
(
...
),
OrderedPlaces AS
(
    SELECT *, 
        Rn = ROW_NUMBER() OVER
            (PARTITION BY CityId, Name
             ORDER BY CASE WHEN Postcode IS NOT NULL THEN 1 ELSE 2 END, 
                      PlaceID)
    FROM Places  
)
SELECT PlaceId, CityId, Name, Postcode 
FROM OrderedPlaces
WHERE Rn = 1 ;

答案 1 :(得分:1)

这个怎么样......

CREATE TABLE #PLACES
( PlaceId int, CityId int, Name varchar(50), Postcode varchar(50)
)
INSERT INTO #PLACES (PlaceId, CityId, Name)VALUES(1, 1, 'Place1' )
INSERT INTO #PLACES (PlaceId, CityId, Name, Postcode)VALUES(2, 1, 'Place1','10000' )
INSERT INTO #PLACES (PlaceId, CityId, Name, Postcode)VALUES(3, 2, 'Place1' , '10300')
INSERT INTO #PLACES (PlaceId, CityId, Name, Postcode)VALUES(4, 2, 'Place2','10500' )
INSERT INTO #PLACES (PlaceId, CityId, Name)VALUES(5, 3, 'Place3' )
INSERT INTO #PLACES (PlaceId, CityId, Name)VALUES(6, 3, 'Place3' )

---查询

;WITH CTE_RESULTS AS
(
    SELECT ROW_NUMBER() OVER (PARTITION BY CityId, Name ORDER BY Postcode DESC) ROW_NO, PlaceId , CityId, Name, Postcode
    FROM #PLACES
)
SELECT * FROM CTE_RESULTS WHERE ROW_NO=1