为了举例说明,假设我有两个表,如下所示:

VehicleID Name
1         Chuck
2         Larry

LocationID VehicleID City
1          1         New York
2          1         Seattle
3          1         Vancouver
4          2         Los Angeles
5          2         Houston

我想写一个查询来返回以下结果:

VehicleID Name    Locations
1         Chuck   New York, Seattle, Vancouver
2         Larry   Los Angeles, Houston

我知道这可以使用服务器端游标来完成,即:

DECLARE @VehicleID int
DECLARE @VehicleName varchar(100)
DECLARE @LocationCity varchar(100)
DECLARE @Locations varchar(4000)
DECLARE @Results TABLE
(
  VehicleID int
  Name varchar(100)
  Locations varchar(4000)
)

DECLARE VehiclesCursor CURSOR FOR
SELECT
  [VehicleID]
, [Name]
FROM [Vehicles]

OPEN VehiclesCursor

FETCH NEXT FROM VehiclesCursor INTO
  @VehicleID
, @VehicleName
WHILE @@FETCH_STATUS = 0
BEGIN

  SET @Locations = ''

  DECLARE LocationsCursor CURSOR FOR
  SELECT
    [City]
  FROM [Locations]
  WHERE [VehicleID] = @VehicleID

  OPEN LocationsCursor

  FETCH NEXT FROM LocationsCursor INTO
    @LocationCity
  WHILE @@FETCH_STATUS = 0
  BEGIN
    SET @Locations = @Locations + @LocationCity

    FETCH NEXT FROM LocationsCursor INTO
      @LocationCity
  END
  CLOSE LocationsCursor
  DEALLOCATE LocationsCursor

  INSERT INTO @Results (VehicleID, Name, Locations) SELECT @VehicleID, @Name, @Locations

END     
CLOSE VehiclesCursor
DEALLOCATE VehiclesCursor

SELECT * FROM @Results

然而,正如您所看到的,这需要大量代码.我想要的是一个通用函数,它允许我做如下事情:

SELECT VehicleID
     , Name
     , JOIN(SELECT City FROM Locations WHERE VehicleID = Vehicles.VehicleID, ', ') AS Locations
FROM Vehicles

这可能吗?还是类似的?

推荐答案

如果您使用的是SQL Server 2005,那么可以使用FOR XML PATH命令.

SELECT [VehicleID]
     , [Name]
     , (STUFF((SELECT CAST(', ' + [City] AS VARCHAR(MAX)) 
         FROM [Location] 
         WHERE (VehicleID = Vehicle.VehicleID) 
         FOR XML PATH ('')), 1, 2, '')) AS Locations
FROM [Vehicle]

这比使用光标容易得多,而且似乎工作得相当好.

Update

对于仍在新版本的SQL Server上使用此方法的人,还有另一种方法,使用

SELECT  [VehicleID]
       ,[Name]
       ,(SELECT STRING_AGG([City], ', ')
         FROM [Location]
         WHERE VehicleID = V.VehicleID) AS Locations
FROM   [Vehicle] V

这还允许将不同的分隔符指定为第二个参数,与前一种方法相比,提供了更大的灵活性.

Sql相关问答推荐

使用`lag()`获取上一个时间戳

删除MariaDB数据库中的JSON数据

LEFT JOIN不显示计数0我期望的方式

如何根据给定条件PostgreSQL迭代减少组中的行数

使用SQL创建列出两个时间戳之间小时数的列

Oracle中的时间戳

在Netezza SQL中将字符DataType转换为整型DataType

仅在日期相隔时递增(Oracle SQL)

合并分层表SQL中的第一个非空、变化的空位置

将用户授予另一个用户不授予权限

更改重复值的情况

不同计数的 Postgres PIVOT 表

当我返回 sql 列时,有没有办法只反转数字? ( hebrew )

SQL 如何根据当前事件和下一个事件确定操作的持续时间?

Clickhouse:左连接表到外部数组

PostgreSQL - 从同一张表中获取值

joins 组合多个重复数据删除策略

在 PostgreSQL 中使用重音敏感排序进行重音不敏感搜索

CURRENT_ROW 窗口框架上的 SQL 滞后

使用 SQL 表中的连接列删除重复记录