半棘手的 SQL 查询
Posted
技术标签:
【中文标题】半棘手的 SQL 查询【英文标题】:Semi-Tricky SQL Query 【发布时间】:2008-10-22 16:00:21 【问题描述】:我正在尝试为 SQL Server 2005 编写查询,但我不知道该怎么做。我有一个包含以下字段的表格:
MessageID int 类别ID int 优先级 tinyint 消息文本 NVARCHAR(MAX)
我需要一个查询,该查询将为类别中具有最高优先级的每一行返回 *。例如,如果我有以下数据:
MessageID、CategoryID、优先级、MessageText 1, 100, 1, 发生错误 #1234 2, 100, 2, 发生错误 #243 3, 100, 3, 发生错误 #976 4、200、4,发生错误 #194 5, 200, 1, 发生错误 #736 6、300、3,发生错误 #54 7, 300, 2, 发生错误 #888
那么结果将是:
MessageID、CategoryID、优先级、MessageText 3, 100, 3, 发生错误 #976 4、200、4,发生错误 #194 6、300、3,发生错误 #54
请注意,它为每个类别返回一行,并且该行是该类别的优先级最高的行。
谁能告诉我如何编写这个查询?
【问题讨论】:
您可以使用 Oracle 中的分析函数更轻松地编写它。 :) 或者使用SQL Server中的解析函数,不用移植到Oracle。 【参考方案1】:已验证:
SELECT
highest_priority_messages.*
FROM
(
SELECT
m.MessageID
, m.CategoryID
, m.Priority
, m.MessageText
, Rank() OVER
(PARTITION BY m.CategoryID ORDER BY m.Priority DESC) AS p_rank
FROM [Message] m
GROUP BY
m.CategoryID
, m.Priority
, m.MessageID
, m.MessageText
) highest_priority_messages
WHERE
p_rank = 1
【讨论】:
您还需要添加一个 CreatedDate 并将其计算到订购等式中,我敢肯定。 你确定这里没有不使用 Rank() 就可以使用 PARTITION 的方法吗? 您可以将 MAX(m.Priority) OVER (PARTITION BY m.CategoryID) 作为 MaxPriority,但是 WHERE 必须将优先级与 MaxPriority 进行比较。这还取决于您是否想要最高优先级的倍数。 这里GROUP BY
有什么用?【参考方案2】:
我相信这应该可行,表名假定为 Messages
SELECT
M.MessageId,
M.CategoryId,
M.Priority,
M.MessageText
FROM
(
SELECT
CategoryId,
MAX(Priority) AS Priority
FROM Messages
GROUP BY CategoryId
) AS MaxValues
INNER JOIN Messages M
ON (MaxValues.CategoryId = M.CategoryId
AND MaxValues.Priority = M.Priority)
注意
此方法中唯一的“陷阱”是,如果您有多个最大优先级...
【讨论】:
【参考方案3】:如果您想在没有所有子查询的情况下这样做:
SELECT
MessageID,
CategoryID,
Priority,
MessageText
FROM
dbo.Messages M1
LEFT OUTER JOIN dbo.Messages M2 ON
M2.CategoryID = M1.CategoryID AND
M2.Priority > M1.Priority
WHERE
M2.MessageID IS NULL
您可能需要根据处理关系的方式调整查询。你没有任何这样的例子,所以我不确定。
【讨论】:
【参考方案4】:select distinct query1.* from
(select categoryId,msgText,max(priorityId) as MAX_PRIORITY
from message
group by categoryId,msgText
order by categoryId
) query1,
(select categoryId,max(priorityId) as MAX_PRIORITY
from message
group by categoryId
order by categoryId
) query2
where query1.MAX_PRIORITY = query2.MAX_PRIORITY
order by query1.categoryId
【讨论】:
【参考方案5】:SELECT
Messages.MessageID
, Messages.CategoryID
, Messages.Priority
, Messages. MessageText
FROM
Messages
INNER JOIN
(
SELECT
CategoryID
, MAX(Priority) AS Priority
FROM
Messages
GROUP BY
CategoryID
) AS MaxResults
ON
(
Messages.CategoryID = MaxResults.CategoryID
AND
Messages.Priority = MaxResults.Priority
)
看起来这与上面给出的答案基本相同......具有相同的警告。
虽然这个可以马上工作。
【讨论】:
【参考方案6】:这更短,更容易阅读 (imo)。
select ms.*
from
messages ms
,(
select ms1.categoryid, max(ms1.priority) as max_priority
from messages ms1
group by ms1.categoryid
) tmp
where ms.categoryid = tmp.categoryid
and ms.priority = tmp.max_priority;
【讨论】:
【参考方案7】:SELECT DISTINCT CategoryId,PS.Priority,MessageID,MessageText
FROM Priority_Scene PS
JOIN (SELECT MAX(Priority) AS Priority FROM Priority_Scene GROUP BY CategoryId) A
ON A.Priority = PS.Priority
【讨论】:
如果同一类别有两个相同且***别的优先级,那么它也将起作用【参考方案8】:我的排名还不够高,无法发表评论,所以我想添加到 cfeduke 的解决方案中:
SELECT
highest_priority_messages.*
FROM
(
SELECT
m.MessageID
, m.CategoryID
, m.Priority
, m.MessageText
, Rank() OVER
(PARTITION BY m.CategoryID ORDER BY m.Priority DESC, m.MessageID DESC) AS p_rank
FROM [Message] m
GROUP BY
m.CategoryID
, m.Priority
, m.MessageID
, m.MessageText
) highest_priority_messages
WHERE
p_rank = 1
如果您添加另一个具有优先级 3 的 CategoryID 100 消息,原始解决方案将带回 2 行,通过添加另一个订单条件,我们消除了两个项目排名相同的机会。
这是我为了测试而插入的行的副本。
insert into [Message] (MessageID, CategoryID, Priority, MessageText)
select 8, 100, 3, 'Error #976-2 occurred'
【讨论】:
以上是关于半棘手的 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章