GROUP BY一列; 为另一个选择任意值

Ant*_*apa 8 sql sql-server

我试图为每个用户选择一行.我不关心我得到的图像.此查询适用于MySQL,但不适用于SQL Server:

SELECT user.id, (images.path + images.name) as 'image_path'
FROM users
JOIN images ON images.user_id = users.id
GROUP BY users.id
Run Code Online (Sandbox Code Playgroud)

小智 14

到目前为止发布的解决方案使用MIN/MAX聚合或ROW_NUMBER可能不是最有效的(取决于数据分布),因为他们通常必须在每组选择一个之前检查所有匹配的行.

使用AdventureWorks示例数据库来说明,以下查询都选择单个,TransactionTypeReferenceOrderID从每个事务历史表中选择ProductID:

使用MIN/ MAXaggregate

SELECT
    p.ProductID,
    MIN(th.TransactionType + STR(th.ReferenceOrderID, 11))
FROM Production.Product AS p
INNER JOIN Production.TransactionHistory AS th ON
    th.ProductID = p.ProductID
GROUP BY
    p.ProductID;
Run Code Online (Sandbox Code Playgroud)

聚合查询计划

运用 ROW_NUMBER

WITH x AS 
(
    SELECT 
        th.ProductID, 
        th.TransactionType, 
        th.ReferenceOrderID,
        rn = ROW_NUMBER() OVER (PARTITION BY th.ProductID ORDER BY (SELECT NULL))
    FROM Production.TransactionHistory AS th
)
SELECT
    p.ProductID,
    x.TransactionType,
    x.ReferenceOrderID
FROM Production.Product AS p
INNER JOIN x ON x.ProductID = p.ProductID
WHERE
    x.rn = 1
OPTION (MAXDOP 1);
Run Code Online (Sandbox Code Playgroud)

行号计划

使用仅内部ANY聚合

SELECT
    q.ProductID, 
    q.TransactionType, 
    q.ReferenceOrderID 
FROM 
(
    SELECT 
        p.ProductID, 
        th.TransactionType, 
        th.ReferenceOrderID,
        rn = ROW_NUMBER() OVER (
            PARTITION BY p.ProductID 
            ORDER BY p.ProductID)
    FROM Production.Product AS p
    JOIN Production.TransactionHistory AS th ON p.ProductID = th.ProductID
) AS q
WHERE
    q.rn = 1;
Run Code Online (Sandbox Code Playgroud)

有关ANY聚合的详细信息,请参阅此博客文章.

任何聚合

使用具有非确定性的相关子查询 TOP

SELECT p.ProductID,
    (
    -- No ORDER BY, so could be any row
    SELECT TOP (1) 
        th.TransactionType + STR( th.ReferenceOrderID, 11)
    FROM Production.TransactionHistory AS th WITH (FORCESEEK) 
    WHERE
        th.ProductID = p.ProductID
    )
FROM Production.Product AS p;
Run Code Online (Sandbox Code Playgroud)

TOP 1

使用CROSS APPLYTOP (1)

上一个查询需要连接并返回NULL没有事务历史记录的产品.使用CROSS APPLYTOP做出决议这两个问题:

SELECT
    p.Name, 
    ca.TransactionType,
    ca.ReferenceOrderID
FROM Production.Product AS p
CROSS APPLY
(
    SELECT TOP (1) 
        th.TransactionType,
        th.ReferenceOrderID
    FROM Production.TransactionHistory AS th WITH (FORCESEEK) 
    WHERE 
        th.ProductID = p.ProductID
) AS ca;
Run Code Online (Sandbox Code Playgroud)

交叉申请计划

通过最佳索引,并且如果每个用户通常具有许多图像,则APPLY可能是最有效的.