【问题标题】:How to Order By within an Order By in SQL?如何在 SQL 中的 Order By 中进行 Order By?
【发布时间】:2011-11-17 18:21:02
【问题描述】:

我正在尝试创建一个 SQL 语句,它将在 SilkCentral 测试管理器中重新创建分层容器/文件夹/测试结构。

  • 测试容器没有 ParentID
  • 测试文件夹包含 ParentID 和 IsLeaf = 0
  • 测试包含 ParentID 和 IsLeaf = 1

此查询会产生所有测试容器、文件夹和测试:

SELECT "NodeID", "ParentID", "Name", "IsLeaf", "OrderNumber"
FROM "Silk"."TM_TestPlanNodes" AS TPN
WHERE PROJECTID = 36
ORDER BY "ParentID", "OrderNumber", "IsLeaf"

以下是部分结果:

NodeID  ParentID    Name                        IsLeaf  OrderNumber 
65408               Installation and Upgrades   0       0   
65445               Connectivity                0       1   
65448               Focus                       0       2   
65409               GINA / PLAP                 0       3   
65446               Graphical User Interface    0       4   
71038               Login Properties            0       5   
65449               Miscellaneous               0       6   
70636               Net Firewall                0       7   
70998               Software Updates            0       8   
65447               Third-party Services        0       9   
70805               SilkTest Automated Tests    0       10  
68812   65408       0. Setup                    0       0
65454   65408       1. Installations & Upgrades 0       1   
65450   65408       Typical/Custom Installation 0       2   

我想要这个顺序:

ParentID 已排序,但如果存在 ParentID=thePreviousNode'sID 的 Node,则选择下一个。如果有多个这样的节点,它们应该按 IsLeaf 排序,然后按 OrderNumber。

如何做到这一点?我能做的非常有限,因为我认为非常复杂的语法最终会在 Silk 中引发错误。我打算尝试一个嵌套的 SELECT 语句:

SELECT "NodeID", "ParentID", "Name","IsLeaf" 
FROM "Silk"."TM_TestPlanNodes" 
WHERE PROJECTID = '36'AND ParentID LIKE (
  SELECT ParentID 
  FROM "Silk"."TM_TestPlanNodes" 
  WHERE NAME = 'Installation and Upgrades')

但出现此错误:“无法执行报告查询:子查询返回超过 1 个值。当子查询遵循 =、!=、、>= 或子查询时,这是不允许的用作表达式。”

这就是我摆弄 Order By 的原因。

【问题讨论】:

    标签: sql sql-order-by


    【解决方案1】:

    您可以使用递归 cte 创建隐藏列并按该列排序。隐藏的列应该是这样的:

    WITH cte (NodeID, ParentID, Name, IsLeaf, [Order])
    AS
    (
        SELECT NodeID, ParentID, Name, IsLeaf, cast(NodeID as nvarchar(10))
        FROM "Silk"."TM_TestPlanNodes" 
        WHERE PROJECTID = '36'
        UNION ALL
        SELECT "NodeID", "ParentID", "Name","IsLeaf", cast(leftNode.ParentID as nvarchar(10)) + cast(leftNode.NodeID as nvarchar(10))
        FROM "Silk"."TM_TestPlanNodes" as leftNode
        INNER JOIN cte on cte.NodeID = leftNode.ParentID
        WHERE leftNode.ParentID = cte.NodeID
    )
    select  "NodeID", "ParentID", "Name","IsLeaf"  from cte
    order by cast([Order] as nvarchar(50))
    

    这是用记事本编写的,因此可能会出现一些错误,但我们的想法是创建一个 [order] 列,例如 65530 将是 654086554569530( parent_parent、父节点和节点)

    编辑

    这仅适用于 id 长度均为 5 个字符的情况,但您可以从这里进行适当的调整。

    【讨论】:

    • 您好丹尼尔,感谢您迄今为止的帮助。我还有一些问题要问你。 1. CTE列定义中[Order]的用途是什么? 2.在第一个SELECT中,你有两次“NodeID”;这是故意的吗? 3. 列数存在计数差异:定义了 6 个,但在两个 Inner SELECT 语句中只有 5 个。 4、如何使定义中[Order]的类型与nvarchar CAST的类型相匹配? 5. 这将适用于多少“深度”?在某些情况下,我们必须向下 8 级才能到达测试用例。谢谢!
    • @rishimaharaj 1 - 排序列是您要从中排序结果的列。 2 - 这是故意的。第一个选择将用于根节点。在这些节点上,顺序值将等于 NodeID,在叶节点上,顺序值将等于 concat(NodeId,LeafId)。 3 - 这是一个错误,我已经编辑了帖子 4 - 与 3 相同。 5- 默认情况下,这可以达到 100 级深度,但您可以配置更多。
    • 谢谢你,丹尼尔。我会在早上尝试并回复您!
    • 你好,丹尼尔。当我尝试编辑后的查询时,我得到SQL statement does not return a ResultSet objectSQL error #1: Types don't match between the anchor and the recursive part in column "Order" of recursive query "cte". 知道如何解决这个问题吗?
    • @rishimaharaj 他说的是 cast(NodeID as nvarchar(10) 的类型不同于 cast(leftNode.ParentID as nvarchar(10) + cast(leftNode.NodeID as nvarchar(10) . 尝试将第一个转换为更大的值,例如 50,并将总和转换为 nvarchar(50)
    【解决方案2】:

    虽然它可能不完美,但它与自联接列表中父子记录的嵌套层次表示非常接近,并包含正确的排序问题。你可能需要为你的桌子稍微调整一下,但是here's a link to a prior solution

    用菜单和相应的数据来澄清这个问题。

    id    |     parentid     |       name
    1     |        0         |      CatOne
    2     |        0         |      CatTwo
    3     |        0         |      CatThree
    4     |        1         |      SubCatOne
    5     |        1         |      SubCatOne2
    6     |        3         |      SubCatThree
    

    期望的输出

    CatOne 1
    --SubCatOne 4
    --SubCatOne2 5
    CatTwo 2
    CatThree 3
    --SubCatThree 6
    

    第一种情况是根据父级对所有类似的 ID 进行预分组...所以,当父级 ID 为 0 时,它是最顶层的,所以我们保留它的 ID。然后,它下面的任何孩子,我们想要他们各自的 PARENT ID,以便所有这些都正确地预先分组。

    SECOND group by 的目的是强制表示实际 TOP LEVEL 菜单项的条目位于列表顶部,而不考虑子条目。

    假设您有一个已经建立 ID 的表,现在您将一个新项目添加到位置 ID = 7 的“新顶级”并希望将 ID #s 2 和 3 移动到新的“顶部-level section。如果你只是用第一个CASE来查询,你的记录会被模拟返回为

    ID   Parent   Name  (natural order from the table)
    2    7        CatTwo
    3    7        CatThree
    7    0        New Category.  (we want THIS one in FIRST POSITION of the group)
    

    如您所见,这将是子分组顺序的错误表示。顶级项目实际上位于第 3 位...为了将其放在前面,我们现在进行子分组并说...如果记录的父 ID = 0,则将其排序为“1”优先级。其他任何东西都被视为“2”优先级,并会模拟类似的结果

    ID   Parent   Name             SubPrioritySort
    7    0        New Category.    1
    2    7        CatTwo           2
    3    7        CatThree         2
    

    由于您实际上并未在结果查询中返回这些“CASE”值,因此您不会以其他方式直观地看到它……但对于咧嘴笑,请将它们作为列添加到您的查询中以查看影响。希望这可以为您澄清答案。

    在您的问题中,您显然可以将排序顺序列添加到此查询的基础上。

    【讨论】:

    • 感谢 DRapp 的建议。我已经尝试了ORDER BY 部分中的CASE 语句,但我无法理解它。我在 MySQL 中创建了一个测试 Table1,其格式与其他问题相同,并尝试了您的解决方案,该解决方案有效。但我不明白你为什么需要ORDER BY 部分的三个部分。一切似乎都适用于第一个 CASE。我通读了你的解释,但我仍然觉得很难理解。您能否进一步说明第二个CASE 到底在做什么以及为什么包含最后一个t1.id
    • @rishimaharaj,为您澄清答案,抱歉延迟回复。
    • 感谢 DRapp 的澄清。与其他潜在解决方案一样,您能说这些案例可以达到多少“深度”?例如,实际上有一个测试用例在顶部以下 10 级。这些案例是否能够处理类似的事情(没有任何连接)?再次感谢!
    • @rishimaharaj,这个版本和一个稍微改变/扩展的版本我已经完成了在单个查询中处理 3 层。从您所看到的完整树视图来看,通常不是由单个查询执行,而是由许多查询执行。初始树视图和可能 1 或 2 个级别将完成。然后,一旦选择了一个级别,它就会递归地将子级别加载到您想要的级别,因此它总是有更深层次的内容供您使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-09
    • 1970-01-01
    相关资源
    最近更新 更多