苦苦寻找正确的WHERE子句

时间:2017-08-22 12:09:56

标签: sql sql-server-2008 ssrs-2008

我正在努力解决SQL查询,我需要你的帮助。说实话,我开始想知道我想要实现的目标是否可以按照我迄今为止的方式完成,但也许你的集体大脑可以提出比我更好的解决方案并证明我采取了良好的方式在开始时(或者我完全错了,我应该从头开始)。

数据集

一行有4个重要字段:ItemIDItemPriorityGroup。这些字段包含唯一有价值的信息,最后将显示的信息。

由于我使用的是SQL Server 2008,因此无法访问LAGLEAD功能,因此我需要对其进行模拟(或者至少,我做过它因为我觉得这对我有用,但我不再那么肯定了。为了获得此结果,我使用了this article from SQLscope中的代码,该代码为您提供了LAGLEAD等效项,我将其限制为具有相同ItemID的一组行。这会为我的数据集添加7个新的功能列:RnRnDiv2RnPlus1Div2PreviousPriorityNextPriority,{{1 }和PreviousGroup

NextGroup

问题

我的SQL查询中的问题是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 子句。我将始终根据其WHERE列过滤行。但有一些微妙之处。无论GroupGroup成员的数量是多少,我希望它根据以下条件显示在一个且只有一个 Item中:

  1. 如果Group出现在同一Item次多次,则只返回Group最低的行。如果priority在同一个Item中出现多次,但具有相同的Group,则只有第一次出现示例: for {{ 1}},只返回Priority值为 5 的行;
  2. 如果Item 2中出现Priority,但Item中的Group也出现Group,则不应显示Priority。{li> 示例: Group 1被选为过滤器。应显示Item 1,但Item 13不应显示,因为Group 8Priority Item 13 Group 8 WHERE只显示Group WHERE Group = 'Group 1' 1}})。
  3. 请注意,这只是一个示例。我的真实数据集有超过3000行,其他一些案例可能是我在样本中没有列出的。

    尝试失败

    就像我说的那样,WHERE Group = 'Group 1' AND (Group = NextGroup AND Priority < NextPriority)子句中有一个常量,即Item过滤。

    • 由于标准#2 ,我不能简单地启动我的条款:Item 13我需要更复杂的东西。
    • 我尝试了以下条款但没有成功:AND NOT (CorrectedPriority >= PreviousPriority)。这对于WHERE不超过2组的情况很有效。但是对于(SiteName <> PreviousSiteName AND CorrectedPriority >= PreviousPriority),它将返回前两行。如果我在Rn = 1子句中添加PreviousSiteName之类的内容,则根本没有结果。
    • 到目前为止的最后一次尝试:NULL。问题是我永远不会返回NULL行,因为WHERE将等于Item。在Item上添加检查也不起作用。在尝试这个特定的条款时,我一定很累,因为它是完整的垃圾。

    我将继续尝试找到好的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. 条款,但我觉得我的整个方法都是错误的。当同一个{{1}}的条目超过两个时,我不知道如何解决问题。值得注意的是,此查询用于 SSRS 报告,因此我可以使用自定义代码来解析数据集并过滤行(使用表格可能有助于解决{{1}}的问题s有两个以上的条目)。但如果这里有一个SQL天才,有一个可行的解决方案,那就太好了。

    PS:如果有人知道如何修复此表并可以向我解释,为他添加额外的cookie。 :d

    编辑:

    这是我目前正在使用的修改后的查询。我会考虑使用@ Yellowbedwetter的最新查询,看起来更强大。

    {{1}}

3 个答案:

答案 0 :(得分:1)

如果我正确理解了这个问题,那么

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 Server版本是否支持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;

答案 1 :(得分:1)

如果我理解你的问题

关于这些标准

  1. 如果项目多次出现在同一组中,则只有 应返回优先级最低的行。示例:for Item 2,只返回优先级值为5的行;

  2. 如果项目出现在群组中,但也出现在另一个群组中 优先级最低的组,不应显示。例: 选择组1作为过滤器。应显示第1项但是项目 13不应该因为它在第8组中也存在较低的 优先级(第13项仅出现在第8组中)。

  3. 我认为我们可以通过使用每个项目的最低优先级而不考虑项目组来获得正确的结果,因为在上述两种情况下,我们采用了项目的最低优先级。

    因此以下查询可能会有所帮助。(我使用您的示例数据对其进行了测试)

    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
    

答案 2 :(得分:0)

Haven没有尝试过,但是......选择max(优先级)作为mp .....来自......其中group =&#39; group1&#39;和mp不在(选择最大(优先)....来自...其中组&lt;&gt;&#39; group1&#39;

打字道歉,在我的手机上没有眼镜:)