Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL按优先级排序_Sql_Sql Server_Sql Server 2008 - Fatal编程技术网

SQL按优先级排序

SQL按优先级排序,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我需要在其他计算的基础上进行计算。这些计算链接到会计代码,因此我需要按照计算优先顺序对代码进行排序。考虑一下:如果x=0.1(y)和0.30(z),z=1+2+3,那么我需要计算z,然后是y,最后是x 下面的示例数据将我的Xs、Ys和Zs表示为我需要计算的会计代码。 对于每一行,我知道第一个字段必须在第二个字段之前计算。我需要完成的是按照计算优先级的顺序获取所有代码 下面是我为解决这个问题而开发的代码。我把这个问题留待讨论,希望有一个更干净/更好的解决办法 DECLARE @tbAccCodes

我需要在其他计算的基础上进行计算。这些计算链接到会计代码,因此我需要按照计算优先顺序对代码进行排序。考虑一下:如果x=0.1(y)和0.30(z),z=1+2+3,那么我需要计算z,然后是y,最后是x

下面的示例数据将我的Xs、Ys和Zs表示为我需要计算的会计代码。
对于每一行,我知道第一个字段必须在第二个字段之前计算。我需要完成的是按照计算优先级的顺序获取所有代码

下面是我为解决这个问题而开发的代码。我把这个问题留待讨论,希望有一个更干净/更好的解决办法

DECLARE @tbAccCodes TABLE (acct_code varchar(50),  process_order int NULL)  
INSERT INTO @tbAccCodes  
VALUES  
('195',NULL),
('220',NULL),
('225',NULL),
('301',NULL),
('304',NULL),
('620',NULL),
('500',NULL),
('510',NULL)

DECLARE @tbCodeDependency TABLE (calc_b4 varchar(50), this varchar(50))  
INSERT INTO @tbCodeDependency  
VALUES  
('195','500'),
('195','510'),
('220','500'),
('220','510'),
('225','220'),
('225','500'),
('225','510'),
('301','500'),
('301','510'),
('304','500'),
('304','510'),
('620','800')

--------------------------------------------------------------------------------
-- Order acct_code codes by calculation precedence
----------------------------------------------------------------------------------
DECLARE @left_acct_code varchar(50), @right_acct_code varchar(50), @left_process_order int, @right_process_order int
DECLARE curCalcPrecedence CURSOR FOR
    SELECT * FROM @tbCodeDependency

--The actual sorting by calculation precedence is done here
OPEN curCalcPrecedence
FETCH NEXT FROM curCalcPrecedence INTO @left_acct_code, @right_acct_code   --- left acct_code depends on right acct_code so left needs to be calculated b4 right
WHILE @@FETCH_STATUS = 0
BEGIN
    SELECT @left_process_order = process_order FROM @tbAccCodes WHERE acct_code = @left_acct_code
    SELECT @right_process_order = process_order FROM @tbAccCodes WHERE acct_code = @right_acct_code

    IF (@left_process_order < @right_process_order)
    BEGIN
        GOTO Cont -- the order is already correct. Go to the next record
    END

    -- both process_order are null so update both to be at the end. Left first then right
    IF(@left_process_order IS NULL AND @right_process_order IS NULL) 
    BEGIN
        SELECT @left_process_order = MAX(ISNULL(process_order,0)) + 1 FROM @tbAccCodes 
        UPDATE @tbAccCodes SET process_order = @left_process_order WHERE  acct_code = @left_acct_code
        UPDATE @tbAccCodes SET process_order  = @left_process_order + 1 WHERE  acct_code = @right_acct_code
        GOTO Cont
    END

    IF(@left_process_order IS NOT NULL AND @right_process_order IS NOT NULL)
    BEGIN
        -- they are in the wrong order because I already took care of both being not null in the correct order in the first check
        UPDATE @tbAccCodes SET process_order = process_order -1 WHERE process_order < @right_process_order 
        UPDATE @tbAccCodes SET process_order = @right_process_order -1 WHERE acct_code = @left_acct_code
        GOTO Cont
    END

    --left process_order is not null and right is null: update right to be at the end
    IF(@left_process_order IS NOT NULL AND @right_process_order IS NULL)
    BEGIN
        UPDATE  @tbAccCodes SET process_order = (SELECT MAX(process_order) FROM @tbAccCodes) + 1 WHERE  acct_code = @right_acct_code
        GOTO Cont
    END

    --last case left is null, right is not null: update left process order to be before right process order
    IF(@left_process_order IS NULL AND @right_process_order IS NOT NULL)
    BEGIN 
        UPDATE @tbAccCodes SET process_order = process_order +1 WHERE process_order > @right_process_order -1 --  NOTE: > @right_process_order -1 is more efficient than >=right_process_order
        UPDATE @tbAccCodes SET process_order = @right_process_order WHERE acct_code = @left_acct_code
        GOTO Cont
    END

Cont:
    ------------------------------------------------------------------------------------------------------------------------
    --test line to see each iteration
    --select * from @tbAccCodes ORDER BY process_order 
    --end test
    ------------------------------------------------------------------------------------------------------------------------

    FETCH NEXT FROM curCalcPrecedence INTO @left_acct_code, @right_acct_code
END
CLOSE curCalcPrecedence
DEALLOCATE curCalcPrecedence

SELECT * FROM @tbAccCodes ORDER BY process_order
DECLARE@tbAccCodes表(acct\u code varchar(50),process\u order int NULL)
插入@tbAccCodes
价值观
('195',空),
('220',空),
('225',空),
('301',空),
('304',空),
('620',空),
('500',空),
('510',空)
声明@tbCodeDependency表(calc_b4 varchar(50),此varchar(50))
插入@tbCodeDependency
价值观
('195','500'),
('195','510'),
('220','500'),
('220','510'),
('225','220'),
('225','500'),
('225','510'),
('301','500'),
('301','510'),
('304','500'),
('304','510'),
('620','800')
--------------------------------------------------------------------------------
--按计算优先级排序的订单会计代码
----------------------------------------------------------------------------------
声明@left\u acct\u code varchar(50)、@right\u acct\u code varchar(50)、@left\u process\u order int、@right\u process\u order int
为声明curcalcRecessence游标
从@tbCodeDependency中选择*
--按计算优先级进行的实际排序在此处完成
开放式现金凭证
从curcalcprecess获取下一个到@left\u acct\u code,@right\u acct\u code--left acct\u code取决于right acct\u code,因此left需要计算为b4 right
而@@FETCH\u STATUS=0
开始
从@tbAccCodes中选择@left\U process\U order=process\U order,其中acct\U code=@left\U acct\U code
从@tbAccCodes中选择@right\u process\u order=process\u order,其中acct\u code=@right\u acct\u code
IF(@左\处理\顺序<@右\处理\顺序)
开始
转到继续--顺序已经正确。转到下一张唱片
终止
--这两个进程的顺序都为空,因此将两者都更新为结尾。先左后右
IF(@left\u process\u order为空,@right\u process\u order为空)
开始
从@tbAccCodes中选择@left\u process\u order=MAX(ISNULL(process\u order,0))+1
更新@tbAccCodes SET process\ U order=@left\ U process\ U order,其中acct\ U code=@left\ U acct\ U code
更新@tbAccCodes SET process\U order=@left\U process\U order+1,其中acct\U code=@right\U acct\U code
转到Cont
终止
IF(@left\u process\u order不为空,@right\u process\u order不为空)
开始
--它们的顺序是错误的,因为我已经在第一次检查中按照正确的顺序处理了它们
更新@tbAccCodes SET process_order=process_order-1,其中process_order<@right_process_order
更新@tbAccCodes SET process\U order=@right\U process\U order-1,其中acct\U code=@left\U acct\U code
转到Cont
终止
--左进程顺序不为空,右进程顺序为空:将右进程更新为结尾
IF(@left\u process\u order不为空,@right\u process\u order为空)
开始
更新@tbAccCodes SET process\U order=(从@tbAccCodes)+1中选择MAX(process\U order),其中acct\U code=@right\U acct\U code
转到Cont
终止
--最后一种情况left为null,right不为null:将left流程订单更新为在right流程订单之前
IF(@left\u process\u order为空,@right\u process\u order不为空)
开始
更新@tbAccCodes SET process\U order=process\U order+1,其中process\U order>@right\U process\U order-1--注意:>@right\U process\U order-1比>=right\U process\U order更有效
更新@tbAccCodes SET process\ U order=@right\ U process\ U order其中acct\ U code=@left\ U acct\ U code
转到Cont
终止
续:
------------------------------------------------------------------------------------------------------------------------
--测试行以查看每个迭代
--从@tbAccCodes ORDER BY process\u ORDER中选择*
--结束测试
------------------------------------------------------------------------------------------------------------------------
从curcalcprecessence获取下一个到@left\u act\u code、@right\u act\u code
终止
关闭当前接收
解除分配当前凭证
从@tbAccCodes ORDER BY process\u ORDER中选择*
数据集是动态的,不允许循环引用

如果这有助于更好地理解这个问题,那么让我来到这里的最初要求是:

允许最终用户输入%值和代码列表以计算代码。所以 代码240=(用户输入的代码列表)值总和的(用户输入的%)
代码301=(用户输入的代码列表)值总和的(用户输入的%)
代码195=(用户输入的代码列表)值总和的(用户输入的%)
...

此外,“用户输入的代码列表”可以是单个代码、用逗号分隔的代码、代码范围以及要从包含范围中排除的代码和代码范围

示例:代码240=代码301304200-299.99,-220,-260-270的值总和的10%

使用逗号拆分上述内容,其内容如下: 添加310
添加304
添加200和299.99之间的所有代码
删除代码220
删除260到270之间的所有代码

所有这些都只是为了240。240计算中包含的所有代码都需要在240之前计算

那么假设195=240的5%

现在,需要在195之前计算240

很抱歉,我的文章太长了,但是我原来简洁的文字造成了混乱,因为ppl错误地认为代码是实际的数字

谢谢你,阿苏米
DECLARE @codes TABLE (dependant varchar(50), dependancy varchar(50))  
INSERT INTO @codes  
VALUES  
('','195'),
('195','304'),   
('225','290'),
('304','220'), 
('301','225'),  
('220','301'),  
('290','')

;with r_cte (code)
as (select dependant from @codes where dependancy = ''
    union all
    select dependant 
    from @codes c
        inner join r_cte r
            on r.code = c.dependancy
    where c.dependant <>  '')
select * from r_cte