我有两张桌子,我想从一对多的桌子获得MAX(日期)。如果没有值,则应为NULL。我只知道如何通过子查询来实现它,但如果有大约20种不同类型,那么20个子查询听起来效率不够。有没有更好的方法呢?
Table A: UserId | Name 1 | John 2 | Jane Table B: UserId | Type | Date 1 | A | 2015-01-01 1 | A | 2015-12-31 1 | B | 2015-01-01 1 | B | 2015-12-31 2 | B | 2015-06-06 1 | C | 2015-01-01 2 | C | 2015-09-09 Result: UserId | Type A date | Type B date | Type C date 1 | 2015-12-31 | 2015-12-31 | NULL 2 | NULL | 2015-06-06 | 2015-09-09
Current solution: SELECT UserId, (SELECT MAX(Date) FROM B WHERE Type = 'A' AND B.UserId= A.UserId), (SELECT MAX(Date) FROM B WHERE Type = 'B' AND B.UserId= A.UserId), (SELECT MAX(Date) FROM B WHERE Type = 'C' AND B.UserId= A.UserId AND Date > (SELECT MAX(Date) FROM B WHERE Type = 'B' AND B.UserId = A.UserId)) FROM A
感谢您的快速解答!他们工作得很好。我修改了我的问题,因为我注意到我需要在某些类型上添加一些条件。例如。如果类型C大于类型B,则应仅显示类型。
答案 0 :(得分:4)
要获得预期结果,您甚至不需要join
,只需执行group by
并使用case
表达式执行条件聚合:
select userid,
max(case when type = 'A' then date end) Adate,
max(case when type = 'B' then date end) Bdate
from tableB
group by userid
如果您还想要用户名,可以使用以上查询加入tableA:
select a.name, b.Adate, b.Bdate
from tableA a
join (select userid,
max(case when type = 'A' then date end) Adate,
max(case when type = 'B' then date end) Bdate
from tableB
group by userid) b
on a.userid = b.userid
但是,如果类型的数量未知,我也会按列类型进行分组。即返回不同行中的类型。
select a.name, b.type, b.date
from tableA a
left join (select userid, type, max(date) date,
from tableB
group by userid, type) b
on a.userid = b.userid
答案 1 :(得分:2)
您可以在SELECT
:
SELECT
a.UserId,
MAX(CASE WHEN b.Type = 'A' THEN b.date END) AS ADate,
MAX(CASE WHEN b.Type = 'B' THEN b.date END) AS BDate
FROM TableA a
LEFT JOIN TableB b
ON b.UserId = a.UserId
GROUP BY a.UserId;
但是,只有了解Type
的值,上述内容才有效。如果不这样做,则需要使用动态查询。
DECLARE @sql NVARCHAR(MAX) = N'';
SELECT @sql =
'SELECT
a.UserId' + CHAR(10) +
(SELECT DISTINCT
' , MAX(CASE WHEN b.Type = ''' + Type + ''' THEN b.Date END) AS ' + QUOTENAME(Type + 'Date') + CHAR(10)
FROM TableB
FOR XML PATH('')
) +
'FROM TableA a
LEFT JOIN TableB b
ON b.UserId = a.UserId
GROUP BY a.UserId;';
EXEC (@sql);
答案 2 :(得分:2)
使用Dynamic Pivot,无论您拥有多少类型,都不需要更改查询。
DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX)
SELECT @ColumnName = ISNULL(@ColumnName + ',','') + QUOTENAME([TYPE])
FROM (SELECT DISTINCT [TYPE] as [TYPE] FROM [master].[dbo].[YourTable]) AS TypeTable
SET @DynamicPivotQuery =
'SELECT USERID,' + @ColumnName+'
FROM [master].[dbo].[YourTable]
PIVOT(MAX([Date])
FOR [TYPE] IN (' + @ColumnName+')) AS PVTTable'
EXEC sp_executesql @DynamicPivotQuery
结果如下:
USERID A B
1 2015-12-31 2015-12-31
2 NULL 2015-06-06
编辑:对于类型C,有一些条件:
DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX)
DECLARE @ColumnNameForDisplay AS NVARCHAR(MAX)
DECLARE @otherCondition AS NVARCHAR(MAX)
SELECT @ColumnName = ISNULL(@ColumnName + ',','') + QUOTENAME([TYPE])
FROM (SELECT DISTINCT [TYPE] as [TYPE] FROM [master].[dbo].[YourTable]) AS TypeTable
SELECT @ColumnNameForDisplay = ISNULL(@ColumnNameForDisplay + ',','') + [TYPE2]
FROM (SELECT DISTINCT [TYPE]+' as [Type '+[TYPE]+' date]' as [TYPE2] FROM [master].[dbo].[YourTable] where type <> 'c') AS TypeTable
SELECT @otherCondition = ' ,Case when c <= b then null else c END as [Type C date] '
SET @DynamicPivotQuery = '
SELECT USERID,'+@ColumnNameForDisplay+@otherCondition+' from(
SELECT USERID,' + @ColumnName+'
FROM [master].[dbo].[YourTable]
PIVOT(MAX([Date])
FOR [TYPE] IN (' + @ColumnName+')) AS PVTTable) as t'
EXEC sp_executesql @DynamicPivotQuery
结果如下:
USERID Type A date Type B date Type C date
1 2015-12-31 2015-12-31 NULL
2 NULL 2015-06-06 2015-09-09