用 Sybase 中的另一个类似选项替换 Lag() 函数

Substitute the Lag() function with another similiar option in Sybase

在 Whosebug 中一些用户的帮助下,我完成了以下查询。问题是此查询在 SQL 服务器中运行良好,但在 Sybase 中运行良好,因为它不支持 LAG()。我一直在努力让它工作但没有成功。

查询非常复杂,但如果能帮助用类似的东西替换 LAG() 函数,我们将不胜感激。

SELECT created
    , bname
    , total_share
FROM (
    SELECT TT.created
        , TT.bname
        , TT.total_share
        , lag(TT.total_share) OVER (
            PARTITION BY TT.bname ORDER BY TT.created
            ) AS prev_share
    FROM (
        SELECT DISTINCT t.created AS created
            , t.NAME AS bname
            , t.total_share
        FROM (
            SELECT cast(fsp.created AS VARCHAR(19)) AS created
                , e.NAME
                , e.initials
                , fsp.modified
                , CASE 
                    WHEN cl.price_per_item = 0
                        THEN CAST('' AS DECIMAL(18, 2))
                    ELSE CAST((fsp.new_price / cl.price_per_item * 100) AS DECIMAL(18, 2))
                    END AS new_share
                , CASE 
                    WHEN cl.price_per_item = 0
                        THEN CAST('' AS DECIMAL(18, 2))
                    ELSE CAST((prev / cl.price_per_item * 100) AS DECIMAL(18, 2))
                    END AS old_share
                , fs.STATE
                , CASE 
                    WHEN fsp.prev_price IS NULL
                        THEN 0
                    ELSE fsp.prev_price
                    END AS prev
                , fsp.new_price AS nprice
                , (prev - nprice) AS diff
                , new_share - old_share AS diff_share
                , old_share + diff_share AS total_share
            FROM project_manager pm
            INNER JOIN dba.project p ON pm.project = p.id
            LEFT JOIN dba.contract c ON p.id = c.project
            LEFT JOIN dba.contract_line cl ON cl.contract = c.id
            LEFT JOIN dba.product pt ON cl.product = pt.id
            LEFT JOIN dba.specified_product sp ON sp.product = pt.id
            LEFT JOIN dba.frozen_sale fs ON fs.spec_product = sp.id
                AND fs.contract = c.id
                AND fs.line = cl.idx
            LEFT JOIN dba.frozen_sale_split fsp ON fsp.frozen_sale = fs.id
                AND fsp.employee = pm.consultant
            LEFT JOIN dba.employee e ON fsp.employee = e.person
            LEFT JOIN dba.person ps ON fsp.creator = ps.id
            WHERE p.id = 50000002735
                AND e.NAME IS NOT NULL
            ) AS t

        ) TT /* here */
    ) x
WHERE (
        prev_share IS NULL
        OR prev_share  total_share
        )
ORDER BY created
    , bname

以下代码未经测试,但做法是使用row_number window函数为每一行分配一个序号(代码中的rnum),按created 值。这是在初始 CTE 中完成的。然后主查询将该 CTE 连接到自身,连接条件为 rnum 值相差 1。

 with inp as (
    SELECT TT.created
        , TT.bname
        , TT.total_share
        , row_number over(order by TT.created) as rnum
    FROM (
        SELECT DISTINCT t.created AS created
            , t.NAME AS bname
            , t.total_share
        FROM (
            SELECT cast(fsp.created AS VARCHAR(19)) AS created
                , e.NAME
                , e.initials
                , fsp.modified
                , CASE 
                    WHEN cl.price_per_item = 0
                        THEN CAST('' AS DECIMAL(18, 2))
                    ELSE CAST((fsp.new_price / cl.price_per_item * 100) AS DECIMAL(18, 2))
                    END AS new_share
                , CASE 
                    WHEN cl.price_per_item = 0
                        THEN CAST('' AS DECIMAL(18, 2))
                    ELSE CAST((prev / cl.price_per_item * 100) AS DECIMAL(18, 2))
                    END AS old_share
                , fs.STATE
                , CASE 
                    WHEN fsp.prev_price IS NULL
                        THEN 0
                    ELSE fsp.prev_price
                    END AS prev
                , fsp.new_price AS nprice
                , (prev - nprice) AS diff
                , new_share - old_share AS diff_share
                , old_share + diff_share AS total_share
            FROM project_manager pm
            INNER JOIN dba.project p ON pm.project = p.id
            LEFT JOIN dba.contract c ON p.id = c.project
            LEFT JOIN dba.contract_line cl ON cl.contract = c.id
            LEFT JOIN dba.product pt ON cl.product = pt.id
            LEFT JOIN dba.specified_product sp ON sp.product = pt.id
            LEFT JOIN dba.frozen_sale fs ON fs.spec_product = sp.id
                AND fs.contract = c.id
                AND fs.line = cl.idx
            LEFT JOIN dba.frozen_sale_split fsp ON fsp.frozen_sale = fs.id
                AND fsp.employee = pm.consultant
            LEFT JOIN dba.employee e ON fsp.employee = e.person
            LEFT JOIN dba.person ps ON fsp.creator = ps.id
            WHERE p.id = 50000002735
                AND e.NAME IS NOT NULL
            ) AS t
        ) TT
    ) 
SELECT
    created
    , bname
    , total_share
    , prev.total_share as prev_share
FROM
    inp
    left join inp as prev on prev.rnum=inp.rnum-1
        and prev.bname=inp.bname
WHERE (
    prev.total_share IS NULL
    OR prev.total_share  total_share
    )
ORDER BY 
    created
    , bname