努力寻找正确的 WHERE 子句
Struggling to find the right WHERE clause
我正在努力处理 SQL 查询,我需要您的帮助。老实说,我开始怀疑我想要实现的目标是否可以像我目前所做的那样完成,但也许你们的集体头脑可以想出比我更好的解决方案,并证明我在开始(或者我完全错了,我应该从头开始)。
数据集
一行有4个重要字段:ItemID
、Item
、Priority
和Group
。这些字段包含唯一有价值的信息,即最后将显示的信息。
因为我使用的是 SQL Server 2008,所以我无法访问 LAG
和 LEAD
函数,所以我需要模拟它们(或者至少,我这样做是因为我认为它对我有用,但我不再那么确定了)。为获得此结果,我使用了 this article from SQLscope 中的代码,它为您提供了 LAG
和 LEAD
等价物,我将其限制为具有相同 ItemID
的一组行。这会向我的数据集添加 7 个新的 functional 列:Rn
、RnDiv2
、RnPlus1Div2
、PreviousPriority
、NextPriority
、 PreviousGroup
和 NextGroup
.
ItemID | Item | Priority | Group | Rn | RnDiv2 | RnPlus1Div2 | PreviousPriority | NextPriority | PreviousGroup | NextGroup
-------- | ------- | -------- | ------- | ----- | ------ | ----------- | ---------------- | ------------ | ------------- | ---------
16777397 | Item 1 | 5 | Group 1 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777403 | Item 2 | 5 | Group 2 | 1 | 0 | 1 | NULL | 5 | NULL | Group 2
16777403 | Item 2 | 10 | Group 2 | 2 | 1 | 1 | 5 | NULL | Group 2 | NULL
16777429 | Item 3 | 1000 | Group 3 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777430 | Item 4 | 5 | Group 1 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777454 | Item 5 | 5 | Group 4 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777455 | Item 6 | 5 | Group 5 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777459 | Item 6 | 5 | Group 6 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777468 | Item 8 | 5 | Group 7 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777479 | Item 9 | 5 | Group 4 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777481 | Item 10 | 5 | Group 4 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777496 | Item 11 | 5 | Group 6 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777514 | Item 12 | 5 | Group 4 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777518 | Item 13 | 5 | Group 8 | 1 | 0 | 1 | NULL | 10 | NULL | Group 8
16777518 | Item 13 | 10 | Group 8 | 2 | 1 | 1 | 5 | 100 | Group 8 | Group 1
16777518 | Item 13 | 100 | Group 1 | 3 | 1 | 2 | 10 | NULL | Group 8 | NULL
16777520 | Item 14 | 5 | Group 9 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
问题
我的 SQL 查询中的问题是 WHERE
子句。我将始终根据 Group
列过滤行。但也有一些微妙之处。无论 Group
和 Item
的成员数量是多少,我都希望它根据这些标准出现在 一个且只有一个 Group
中:
- 如果
Item
在同一个 Group
中出现不止一次,只有最低 priority
的行应该被 return 编辑。如果 Item
在同一个 Group
中出现多次,但具有相同的 Priority
,则只应保留第一次出现的 例如:对于 Item 2
,只有 Priority
值为 5 的行应该 returned;
- 如果
Item
出现在 Group
中,但也出现在另一个具有最低 Priority
的 Group
中,则不应显示。 示例: Group 1
被选为过滤器。 Item 1
应该显示,但 Item 13
不应该显示,因为它也出现在 Group 8
中,但 Priority
较低(Item 13
只会出现在 Group 8
).
请注意,这只是一个示例。我的真实数据集有 3000 多行,其他一些情况可能是我没有在示例中列出的。
尝试失败
正如我所说,WHERE
子句中有一个常量,那就是 Group
过滤。
- 由于 标准 #2,我不能简单地开始我的子句:
WHERE Group = 'Group 1'
我需要更复杂的东西。
- 我尝试了以下子句但没有成功:
WHERE Group = 'Group 1' AND (Group = NextGroup AND Priority < NextPriority)
。这在不超过 2 个组的 Item
的情况下效果很好。但是对于 Item 13
,它会 return 前两行。如果我在 WHERE
子句中添加类似 AND NOT (CorrectedPriority >= PreviousPriority)
的内容,我根本得不到任何结果。
- 到目前为止的最后一次尝试:
(SiteName <> PreviousSiteName AND CorrectedPriority >= PreviousPriority)
。问题是我永远不会 return 一行 Rn = 1
因为 PreviousSiteName
将等于 NULL
。添加对 NULL
的检查也不起作用。尝试这个特定的条款时我一定很累,因为它完全是垃圾。
我会继续尝试找到好的 WHERE
子句,但我觉得我的整个方法都是错误的。当同一个 Item
有两个以上的条目时,我不知道如何解决问题。值得注意的是,此查询用于 SSRS 报告,因此我可以使用自定义代码来解析数据集并过滤行(使用 tables 可能有助于解决包含两个以上条目的 Item
s 的问题)。但是,如果这里有 SQL 天才提供可行的解决方案,那就太好了。
PS : 如果有人知道如何解决这个 table 并且可以向我解释,给他额外的饼干。 :D
编辑:
这是我目前正在使用的修改后的查询。我会考虑使用@Yellowbedwetter 的最新查询,因为它看起来更可靠。
SELECT *
FROM (SELECT ItemID,
Item,
Priority,
Group_,
MIN(Priority) OVER
( PARTITION BY item
) AS interItem_MinPriority
FROM (SELECT ItemID,
Item,
Priority,
Group_,
ROW_NUMBER() OVER
( PARTITION BY Item
ORDER BY Priority ASC
) AS interGrp_Rank
FROM Test_Table
) AS TMP
WHERE interGrp_Rank = 1 -- Exclude all records with the same item/group, but higher priority.
) AS TMP2
WHERE Priority = interItem_MinPriority; -- Exclude which aren't the lowest priority across groups.
没试过,但是类似..`select max(priority) as mp ..... From ... Where group = 'group1' and mp not in (select max(priority).... from ... Where group <> 'group1'
抱歉打字,我 phone 没戴眼镜 :)
如果我正确理解问题,这应该有效
SELECT *
FROM (SELECT ItemID,
Item,
Priority,
Group_,
MIN(Priority) OVER
( PARTITION BY item
) AS interItem_MinPriority
FROM (SELECT ItemID,
Item,
Priority,
Group_,
ROW_NUMBER() OVER
( PARTITION BY Item,
Group_
ORDER BY Priority ASC
) AS interGrp_Rank
FROM Test_Table
) AS TMP
WHERE interGrp_Rank = 1 -- Exclude all records with the same item/group, but higher priority.
) AS TMP2
WHERE Priority = interItem_MinPriority; -- Exclude which aren't the lowest priority across groups.
我不知道你的 SQL 服务器版本是否支持 MIN() OVER()...,但如果不支持,你应该能够很容易地解决这个问题。
编辑: 处理平局。
WITH TEST_TABLE (ItemID, Item, Priority, Group_) AS
(
SELECT '16777397','Item 1','5','Group 1' UNION
SELECT '16777403','Item 2','5','Group 2' UNION
SELECT '16777403','Item 2','10','Group 2' UNION
SELECT '16777429','Item 3','1000','Group 3' UNION
SELECT '16777430','Item 4','5','Group 1' UNION
SELECT '16777454','Item 5','5','Group 4' UNION
SELECT '16777455','Item 6','5','Group 5' UNION
SELECT '16777459','Item 6','5','Group 6' UNION
SELECT '16777468','Item 8','5','Group 7' UNION
SELECT '16777479','Item 9','5','Group 4' UNION
SELECT '16777481','Item 10','5','Group 4' UNION
SELECT '16777496','Item 11','5','Group 6' UNION
SELECT '16777514','Item 12','5','Group 4' UNION
SELECT '16777518','Item 13','5','Group 8' UNION
SELECT '16777518','Item 13','10','Group 8' UNION
SELECT '16777518','Item 13','100','Group 1' UNION
SELECT '16777520','Item 14','5','Group 9'
)
SELECT ItemID,
Item,
Priority,
Group_
FROM (SELECT ItemID,
Item,
Priority,
Group_,
ROW_NUMBER() OVER
( PARTITION BY item
ORDER BY Group_ ASC -- or however you want to break the tie
) AS grp_minPriority_TieBreak
FROM (SELECT ItemID,
Item,
Priority,
Group_,
MIN(Priority) OVER
( PARTITION BY item
) AS interItem_MinPriority
FROM (SELECT ItemID,
Item,
Priority,
Group_,
ROW_NUMBER() OVER
( PARTITION BY Item,
Group_
ORDER BY Priority ASC
) AS interGrp_Rank
FROM TEST_TABLE
) AS TMP
WHERE interGrp_Rank = 1 -- Exclude all records with the same item/group, but higher priority.
) AS TMP2
WHERE Priority = interItem_MinPriority -- Exclude which aren't the lowest priority across groups.
) AS TMP2
WHERE grp_minPriority_TieBreak = 1;
如果我理解你的问题
关于这些标准
如果该项目多次出现在同一个组中,则只
应返回优先级最低的行。示例:对于项目
2、只返回Priority值为5的行;
如果该项目出现在组中但也出现在另一个组中
优先级最低的组,不应显示。例子:
选择第 1 组作为过滤器。应显示项目 1,但项目
13 不应该,因为它也出现在第 8 组中,具有较低的
优先级(项目 13 只会出现在第 8 组中)。
我认为我们可以在不考虑item组的情况下使用每个item的最小优先级得到正确的结果,因为在上面的两种情况下我们都采用了item的最小优先级
所以下面的查询可能会有帮助。(我用你的样本数据测试过)
with minPriority as
(
select ItemID, Item, Priority , Group_,ROW_NUMBER() over(partition by ItemId order by priority )rn from Test_table
)
select * from minPriority where rn=1
我正在努力处理 SQL 查询,我需要您的帮助。老实说,我开始怀疑我想要实现的目标是否可以像我目前所做的那样完成,但也许你们的集体头脑可以想出比我更好的解决方案,并证明我在开始(或者我完全错了,我应该从头开始)。
数据集
一行有4个重要字段:ItemID
、Item
、Priority
和Group
。这些字段包含唯一有价值的信息,即最后将显示的信息。
因为我使用的是 SQL Server 2008,所以我无法访问 LAG
和 LEAD
函数,所以我需要模拟它们(或者至少,我这样做是因为我认为它对我有用,但我不再那么确定了)。为获得此结果,我使用了 this article from SQLscope 中的代码,它为您提供了 LAG
和 LEAD
等价物,我将其限制为具有相同 ItemID
的一组行。这会向我的数据集添加 7 个新的 functional 列:Rn
、RnDiv2
、RnPlus1Div2
、PreviousPriority
、NextPriority
、 PreviousGroup
和 NextGroup
.
ItemID | Item | Priority | Group | Rn | RnDiv2 | RnPlus1Div2 | PreviousPriority | NextPriority | PreviousGroup | NextGroup
-------- | ------- | -------- | ------- | ----- | ------ | ----------- | ---------------- | ------------ | ------------- | ---------
16777397 | Item 1 | 5 | Group 1 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777403 | Item 2 | 5 | Group 2 | 1 | 0 | 1 | NULL | 5 | NULL | Group 2
16777403 | Item 2 | 10 | Group 2 | 2 | 1 | 1 | 5 | NULL | Group 2 | NULL
16777429 | Item 3 | 1000 | Group 3 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777430 | Item 4 | 5 | Group 1 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777454 | Item 5 | 5 | Group 4 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777455 | Item 6 | 5 | Group 5 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777459 | Item 6 | 5 | Group 6 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777468 | Item 8 | 5 | Group 7 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777479 | Item 9 | 5 | Group 4 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777481 | Item 10 | 5 | Group 4 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777496 | Item 11 | 5 | Group 6 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777514 | Item 12 | 5 | Group 4 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
16777518 | Item 13 | 5 | Group 8 | 1 | 0 | 1 | NULL | 10 | NULL | Group 8
16777518 | Item 13 | 10 | Group 8 | 2 | 1 | 1 | 5 | 100 | Group 8 | Group 1
16777518 | Item 13 | 100 | Group 1 | 3 | 1 | 2 | 10 | NULL | Group 8 | NULL
16777520 | Item 14 | 5 | Group 9 | 1 | 0 | 1 | NULL | NULL | NULL | NULL
问题
我的 SQL 查询中的问题是 WHERE
子句。我将始终根据 Group
列过滤行。但也有一些微妙之处。无论 Group
和 Item
的成员数量是多少,我都希望它根据这些标准出现在 一个且只有一个 Group
中:
- 如果
Item
在同一个Group
中出现不止一次,只有最低priority
的行应该被 return 编辑。如果Item
在同一个Group
中出现多次,但具有相同的Priority
,则只应保留第一次出现的 例如:对于Item 2
,只有Priority
值为 5 的行应该 returned; - 如果
Item
出现在Group
中,但也出现在另一个具有最低Priority
的Group
中,则不应显示。 示例:Group 1
被选为过滤器。Item 1
应该显示,但Item 13
不应该显示,因为它也出现在Group 8
中,但Priority
较低(Item 13
只会出现在Group 8
).
请注意,这只是一个示例。我的真实数据集有 3000 多行,其他一些情况可能是我没有在示例中列出的。
尝试失败
正如我所说,WHERE
子句中有一个常量,那就是 Group
过滤。
- 由于 标准 #2,我不能简单地开始我的子句:
WHERE Group = 'Group 1'
我需要更复杂的东西。 - 我尝试了以下子句但没有成功:
WHERE Group = 'Group 1' AND (Group = NextGroup AND Priority < NextPriority)
。这在不超过 2 个组的Item
的情况下效果很好。但是对于Item 13
,它会 return 前两行。如果我在WHERE
子句中添加类似AND NOT (CorrectedPriority >= PreviousPriority)
的内容,我根本得不到任何结果。 - 到目前为止的最后一次尝试:
(SiteName <> PreviousSiteName AND CorrectedPriority >= PreviousPriority)
。问题是我永远不会 return 一行Rn = 1
因为PreviousSiteName
将等于NULL
。添加对NULL
的检查也不起作用。尝试这个特定的条款时我一定很累,因为它完全是垃圾。
我会继续尝试找到好的 WHERE
子句,但我觉得我的整个方法都是错误的。当同一个 Item
有两个以上的条目时,我不知道如何解决问题。值得注意的是,此查询用于 SSRS 报告,因此我可以使用自定义代码来解析数据集并过滤行(使用 tables 可能有助于解决包含两个以上条目的 Item
s 的问题)。但是,如果这里有 SQL 天才提供可行的解决方案,那就太好了。
PS : 如果有人知道如何解决这个 table 并且可以向我解释,给他额外的饼干。 :D
编辑:
这是我目前正在使用的修改后的查询。我会考虑使用@Yellowbedwetter 的最新查询,因为它看起来更可靠。
SELECT *
FROM (SELECT ItemID,
Item,
Priority,
Group_,
MIN(Priority) OVER
( PARTITION BY item
) AS interItem_MinPriority
FROM (SELECT ItemID,
Item,
Priority,
Group_,
ROW_NUMBER() OVER
( PARTITION BY Item
ORDER BY Priority ASC
) AS interGrp_Rank
FROM Test_Table
) AS TMP
WHERE interGrp_Rank = 1 -- Exclude all records with the same item/group, but higher priority.
) AS TMP2
WHERE Priority = interItem_MinPriority; -- Exclude which aren't the lowest priority across groups.
没试过,但是类似..`select max(priority) as mp ..... From ... Where group = 'group1' and mp not in (select max(priority).... from ... Where group <> 'group1'
抱歉打字,我 phone 没戴眼镜 :)
如果我正确理解问题,这应该有效
SELECT *
FROM (SELECT ItemID,
Item,
Priority,
Group_,
MIN(Priority) OVER
( PARTITION BY item
) AS interItem_MinPriority
FROM (SELECT ItemID,
Item,
Priority,
Group_,
ROW_NUMBER() OVER
( PARTITION BY Item,
Group_
ORDER BY Priority ASC
) AS interGrp_Rank
FROM Test_Table
) AS TMP
WHERE interGrp_Rank = 1 -- Exclude all records with the same item/group, but higher priority.
) AS TMP2
WHERE Priority = interItem_MinPriority; -- Exclude which aren't the lowest priority across groups.
我不知道你的 SQL 服务器版本是否支持 MIN() OVER()...,但如果不支持,你应该能够很容易地解决这个问题。
编辑: 处理平局。
WITH TEST_TABLE (ItemID, Item, Priority, Group_) AS
(
SELECT '16777397','Item 1','5','Group 1' UNION
SELECT '16777403','Item 2','5','Group 2' UNION
SELECT '16777403','Item 2','10','Group 2' UNION
SELECT '16777429','Item 3','1000','Group 3' UNION
SELECT '16777430','Item 4','5','Group 1' UNION
SELECT '16777454','Item 5','5','Group 4' UNION
SELECT '16777455','Item 6','5','Group 5' UNION
SELECT '16777459','Item 6','5','Group 6' UNION
SELECT '16777468','Item 8','5','Group 7' UNION
SELECT '16777479','Item 9','5','Group 4' UNION
SELECT '16777481','Item 10','5','Group 4' UNION
SELECT '16777496','Item 11','5','Group 6' UNION
SELECT '16777514','Item 12','5','Group 4' UNION
SELECT '16777518','Item 13','5','Group 8' UNION
SELECT '16777518','Item 13','10','Group 8' UNION
SELECT '16777518','Item 13','100','Group 1' UNION
SELECT '16777520','Item 14','5','Group 9'
)
SELECT ItemID,
Item,
Priority,
Group_
FROM (SELECT ItemID,
Item,
Priority,
Group_,
ROW_NUMBER() OVER
( PARTITION BY item
ORDER BY Group_ ASC -- or however you want to break the tie
) AS grp_minPriority_TieBreak
FROM (SELECT ItemID,
Item,
Priority,
Group_,
MIN(Priority) OVER
( PARTITION BY item
) AS interItem_MinPriority
FROM (SELECT ItemID,
Item,
Priority,
Group_,
ROW_NUMBER() OVER
( PARTITION BY Item,
Group_
ORDER BY Priority ASC
) AS interGrp_Rank
FROM TEST_TABLE
) AS TMP
WHERE interGrp_Rank = 1 -- Exclude all records with the same item/group, but higher priority.
) AS TMP2
WHERE Priority = interItem_MinPriority -- Exclude which aren't the lowest priority across groups.
) AS TMP2
WHERE grp_minPriority_TieBreak = 1;
如果我理解你的问题
关于这些标准
如果该项目多次出现在同一个组中,则只 应返回优先级最低的行。示例:对于项目 2、只返回Priority值为5的行;
如果该项目出现在组中但也出现在另一个组中 优先级最低的组,不应显示。例子: 选择第 1 组作为过滤器。应显示项目 1,但项目 13 不应该,因为它也出现在第 8 组中,具有较低的 优先级(项目 13 只会出现在第 8 组中)。
我认为我们可以在不考虑item组的情况下使用每个item的最小优先级得到正确的结果,因为在上面的两种情况下我们都采用了item的最小优先级
所以下面的查询可能会有帮助。(我用你的样本数据测试过)
with minPriority as
(
select ItemID, Item, Priority , Group_,ROW_NUMBER() over(partition by ItemId order by priority )rn from Test_table
)
select * from minPriority where rn=1