我有这样一张表category,表结构和内容如下:
slno category uppercategory 1 Mouse Computer 2 Computer Electronics 3 Electronics END 4 END -
上表可以很容易看出其含义。Mouse(鼠标)的上层分类为Computer(电脑),而Computer的上层分类为Electronics(电子产品),再上面不做分类了,就为END。该表记录了各种各样的分类,分类名称唯一,上例只是取了四条样例数据。
现在我的需求是,输入一个分类@Dcat,希望返回其顶层分类名称,即END之下的分类。我尝试了如下代码,但是不起作用:
USE [Database1] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER PROCEDURE [dbo].[kt_category] @Dcat AS NVARCHAR(250) AS DECLARE @tmp TABLE (cater NVARCHAR(255)) BEGIN INSERT INTO @tmp SELECT UPPERCATEGORY FROM CATEGORY where CATEGORY=@Dcat while( SELECT UPPERCATEGORY FROM CATEGORY )= 'END' RETURN END
这样的需求应该如何实现呢
本题来源stackoverflow
本题是典型的递归查询的应用,在Oracle/SQLServer/DB2中都支持使用with来实现递归。具体可以如下:
WITH R AS (SELECT *, 1 AS Level FROM CATEGORY WHERE Category = @Dcat UNION ALL SELECT C.*, R.Level + 1 FROM CATEGORY C JOIN R ON R.Uppercategory = C.Category) SELECT * FROM R WHERE Uppercategory = 'End'
这里利用With生成了一张临时表。
临时表的生成过程是这样的:首先执行union all上部的SQL,对R进行初始化。基于这些初始化数据,再执行union all下部的SQL。执行过程中,依次取R中的每一条记录找出下部查询中的返回,再插入到R中,循环往复,直到union all下部SQL没有记录返回为止。R中记录的处理顺序是基于插入的先后顺序。当R表记录最终确定后,执行with后面的select。
上面给出的解答中,LEVEL其实可以不需要,它的作用是表示出递归的层次,这里也就是category从底向上的层数,可以帮助理解。LEVEL在本题来源中协助进行结果处理,详细见本题来源stackoverflow。
在MySQL环境下,暂时没有类似With的递归处理方法,可以通过循环查询的方式变通,本次不做扩展。
The post 怎样递归的查找最高层次的分类名称 appeared first on SQLParty.