【问题标题】:How to convert the oracle sql to Snowflake sql如何将 oracle sql 转换为 Snowflake sql
【发布时间】:2021-05-11 13:12:18
【问题描述】:

您好,我在 Snowflake 中的选择中调用选择查询。我面临的错误是 INVALID IDENTIFIER AS ROWNUM,当我评论 Rownum 时,我面临的错误是 Unsupported Subquery type cant evaluted。

我的要求是将现有的 oracle 查询转换为 SNowflake。

SELECT DISTINCT cust.Id AS Customer_Id
            ,nvl((
                    SELECT *
                    FROM (
                        SELECT to_char(cliterm.Quantity)
                        FROM ContractLineItemTerm cliterm
                        WHERE cliterm.ContractLineItem_id = cli.Id
                            AND (
                                cliterm.EndDate IS NULL
                                OR cliterm.EndDate > add_months(sysdate, - 3)
                                )
                            AND cliterm.PriceRuleItem_id IS NULL
                        ORDER BY cli.id DESC
                        )
                    WHERE rownum = 1
                    ), cli.Quantity) AS Quantity_Purchased
            ,nvl((
                    SELECT *
                    FROM (
                        SELECT cliterm.UsedQuantity
                        FROM ContractLineItemTerm cliterm
                        WHERE cliterm.ContractLineItem_id = cli.Id
                            AND (
                                cliterm.EndDate IS NULL
                                OR cliterm.EndDate > add_months(sysdate, - 3)
                                )
                            AND cliterm.PriceRuleItem_id IS NULL
                        ORDER BY cli.id DESC
                        )
                    WHERE rownum = 1
                    ), cli.UsedQuantity) AS Quantity_Used_To_Date
            ,nvl((
                    SELECT *
                    FROM (
                        SELECT cliterm.StartDate
                        FROM ContractLineItemTerm cliterm
                        WHERE cliterm.ContractLineItem_id = cli.Id
                            AND (
                                cliterm.EndDate IS NULL
                                OR cliterm.EndDate > add_months(sysdate, - 3)
                                )
                            AND cliterm.PriceRuleItem_id IS NULL
                        ORDER BY cli.id DESC
                        )
                    WHERE rownum = 1
                    ), cli.StartDate) AS sbscription_Term_Start_Date
            ,nvl((
                    SELECT *
                    FROM (
                        SELECT cliterm.EndDate
                        FROM ContractLineItemTerm cliterm
                        WHERE cliterm.ContractLineItem_id = cli.Id
                            AND (
                                cliterm.EndDate IS NULL
                                OR cliterm.EndDate > add_months(sysdate, - 3)
                                )
                            AND cliterm.PriceRuleItem_id IS NULL
                        ORDER BY id DESC
                        )
                    WHERE rownum = 1
                    ), cli.EndDate) AS sbscription_Term_End_Date
            ,nvl(to_char(cli.EndDate), (
                    CASE 
                        WHEN (
                                cli.StartDate IS NOT NULL
                                AND con.InitialTerm > 0
                                )
                            THEN 'Auto Renewal'
                        ELSE ''
                        END
                    )) AS Contr_End_Date
        FROM ContractLineItem cli
        INNER JOIN Contract con ON cli.Contract_id = con.Id
        INNER JOIN Customer cust ON con.Customer_id = cust.Id
        INNER JOIN Organization org ON org.Customer_id = cust.Id
        INNER JOIN Product prod ON cli.Product_id = prod.Id
        INNER JOIN Producttype pt ON prod.ProductBrand_id = pt.Id
        LEFT JOIN account acc ON cust.SAN = acc.acc__c
        LEFT JOIN account acc1 ON acc.parentid = acc1.id
        LEFT JOIN sbSCRIPTION sb ON sb.id = cli.sforceid
        LEFT JOIN sbSCRIPTION pasb ON pasb.id = sb.srequired
        LEFT JOIN scontract1 cntr ON cntr.contractnumber = con.ContNumber
        LEFT JOIN user accowner ON acc.ownerid = accowner.id
        LEFT JOIN user accsalesmanager ON accowner.managerid = accsalesmanager.id
        LEFT JOIN (
            SELECT f.accountid
                ,g.managerid
                ,max(g.NAME) CSM
                ,max(g.id) CSMID
            FROM accountteammember f
            JOIN user g ON f.userid = g.id
            WHERE f.teammemberrole = 'AGM'
            GROUP BY f.accountid
                ,g.managerid
            ) acccsm ON acccsm.accountid = acc.id
        LEFT JOIN product2 prd ON prod.Code = prd.productcode
        LEFT JOIN prdfam prod_fam ON prod_fam.product_family_desc = prd.Product_Family__c
        )
    WHERE Quantity_Purchased <> 0
    );

如何将其转换为支持的雪花,因为它应该根据rownum = 1选择数量列,如果它为null,则应该用一些x替换。

【问题讨论】:

  • 请编辑您的问题以包含完整的 SQL 语句;您不需要提供 SELECT 中的所有列,但您需要包含所有表及其连接逻辑
  • 我提到了完整的 oracle sql 查询,现在需要根据 Snowflake 进行更改。请提出更改建议。
  • 嗨 - 您的每个子选择中的 ORDER BY cli.id 不会做任何事情,因为 SELECT 无论如何都仅限于单个 id(来自连接)。如果这些子选择返回多个记录,那么您将获得随机选择 - 我认为这不是您想要的。对于每个 cli.id,如果有多个,确定从每个子选择返回哪个记录的正确逻辑是什么?

标签: snowflake-cloud-data-platform


【解决方案1】:

尝试将您的查询更改为此(将WHERE rownum = 1更改为limit 1

,nvl((
                    SELECT *
                    FROM (
                        SELECT to_char(cliterm.Quantity)
                        FROM ContractLineItemTerm cliterm
                        WHERE cliterm.ContractLineItem_id = cli.Id
                            AND (
                                cliterm.EndDate IS NULL
                                OR cliterm.EndDate > add_months(sysdate, - 3)
                                )
                            AND cliterm.PriceRuleItem_id IS NULL
                        ORDER BY cli.id DESC
                        )
                    limit 1

【讨论】:

    【解决方案2】:

    示例 SQL 缺少几层 SELECT * FROM (,因为您必须在末尾使用不匹配的括号。但是假设您选择 * 所以您的 WHERE Quantity_Purchased &lt;&gt; 0 这可以转换为 QUALIFY 并且可以跳过层。

    主要有两点,如何转换SQL,如何避免相关子查询

    首先JOIN中的三个sub-select有相同的模式,所以我们将讨论第一个,WHERE rownum = 1可以通过limit 1 order通过QUALIFY完成。我更喜欢后者。

    SELECT to_char(cliterm.Quantity)
    FROM ContractLineItemTerm cliterm
    WHERE cliterm.ContractLineItem_id = cli.Id
        AND (
            cliterm.EndDate IS NULL
            OR cliterm.EndDate > add_months(sysdate, - 3)
            )
        AND cliterm.PriceRuleItem_id IS NULL
    QUALIFY row_numumber() OVER (ORDER BY cli.id DESC) = 1
    

    然后当您在相关子查询中使用它时,这实际上也是随机的,因为您按cli.id 排序,但也加入了同一子句,因此您实际上没有对数据进行排序。所以首先你需要有一个更好的从ContractLineItemTerm 中选择的子句我将组成一个名为is_best 的列,这样SQL 才有意义,然后你可以在里面放一些有意义的东西。

    接下来要注意的是您的四个选择都是同一个 SQL 块,因此我们可以将其更改为一个连接并完成它。

    所以我使用了 CTE,这样您就可以看到四块如何写成一个块,并将您的 JOIN ON 重新格式化为新行,因为对于更复杂的 SQL 它更好,并且我将您的CASE 改写为IFF,因为它是一个简单的两个分支案例。

    WITH best_per_id (
        SELECT cliterm.ContractLineItem_id
            ,to_char(cliterm.Quantity) as Quantity
            ,cliterm.UsedQuantity
            ,cliterm.StartDate
        FROM ContractLineItemTerm cliterm
        WHERE cliterm.PriceRuleItem_id IS NULL
            AND (
                cliterm.EndDate IS NULL
                OR cliterm.EndDate > add_months(sysdate, - 3)
                )
        QUALIFY row_numumber() OVER (PARTITION BY cliterm.ContractLineItem_id 
            ORDER BY cliterm.is_best ) = 1
    )
    SELECT DISTINCT cust.Id AS Customer_Id
        ,nvl(bpi.Quantity, cli.Quantity) AS Quantity_Purchased
        ,nvl(bpi.UsedQuantity, cli.UsedQuantity) AS Quantity_Used_To_Date
        ,nvl(bpi.StartDate, cli.StartDate) AS sbscription_Term_Start_Date
        ,nvl(bpi.EndDate, cli.EndDate) AS sbscription_Term_End_Date
        ,nvl(to_char(cli.EndDate), 
             IFF(cli.StartDate IS NOT NULL AND con.InitialTerm > 0, 'Auto Renewal', '')
            ) AS Contr_End_Date
    FROM ContractLineItem cli
    INNER JOIN Contract con 
        ON cli.Contract_id = con.Id
    INNER JOIN Customer cust 
        ON con.Customer_id = cust.Id
    INNER JOIN Organization org 
        ON org.Customer_id = cust.Id
    INNER JOIN Product prod 
        ON cli.Product_id = prod.Id
    INNER JOIN Producttype pt 
        ON prod.ProductBrand_id = pt.Id
    LEFT JOIN best_per_id as bpi
        ON cli.id = bpi.ContractLineItem_id
    LEFT JOIN account acc 
        ON cust.SAN = acc.acc__c
    LEFT JOIN account acc1 
        ON acc.parentid = acc1.id
    LEFT JOIN sbSCRIPTION sb 
        ON sb.id = cli.sforceid
    LEFT JOIN sbSCRIPTION pasb 
        ON pasb.id = sb.srequired
    LEFT JOIN scontract1 cntr 
        ON cntr.contractnumber = con.ContNumber
    LEFT JOIN user accowner 
        ON acc.ownerid = accowner.id
    LEFT JOIN user accsalesmanager 
        ON accowner.managerid = accsalesmanager.id
    LEFT JOIN (
        SELECT f.accountid
            ,g.managerid
            ,max(g.NAME) CSM
            ,max(g.id) CSMID
        FROM accountteammember f
        JOIN user g ON f.userid = g.id
        WHERE f.teammemberrole = 'AGM'
        GROUP BY f.accountid
            ,g.managerid
        ) acccsm ON acccsm.accountid = acc.id
    LEFT JOIN product2 prd 
        ON prod.Code = prd.productcode
    LEFT JOIN prdfam prod_fam 
        ON prod_fam.product_family_desc = prd.Product_Family__c
    QUALIFY Quantity_Purchased <> 0;
    

    但这都可以写成一个子选择,就像acccsm 一样:

    WITH best_per_id (
        SELECT cliterm.ContractLineItem_id
            ,to_char(cliterm.Quantity) as Quantity
            ,cliterm.UsedQuantity
            ,cliterm.StartDate
        FROM ContractLineItemTerm cliterm
        WHERE cliterm.PriceRuleItem_id IS NULL
            AND (
                cliterm.EndDate IS NULL
                OR cliterm.EndDate > add_months(sysdate, - 3)
                )
        QUALIFY row_numumber() OVER (PARTITION BY cliterm.ContractLineItem_id 
           ORDER BY cliterm.is_best ) = 1
    )
    SELECT DISTINCT cust.Id AS Customer_Id
        ,nvl(bpi.Quantity, cli.Quantity) AS Quantity_Purchased
        ,nvl(bpi.UsedQuantity, cli.UsedQuantity) AS Quantity_Used_To_Date
        ,nvl(bpi.StartDate, cli.StartDate) AS sbscription_Term_Start_Date
        ,nvl(bpi.EndDate, cli.EndDate) AS sbscription_Term_End_Date
        ,nvl(to_char(cli.EndDate), 
             IFF(cli.StartDate IS NOT NULL AND con.InitialTerm > 0, 'Auto Renewal', '')
            ) AS Contr_End_Date
    FROM ContractLineItem cli
    INNER JOIN Contract con 
        ON cli.Contract_id = con.Id
    INNER JOIN Customer cust 
        ON con.Customer_id = cust.Id
    INNER JOIN Organization org 
        ON org.Customer_id = cust.Id
    INNER JOIN Product prod 
        ON cli.Product_id = prod.Id
    INNER JOIN Producttype pt 
        ON prod.ProductBrand_id = pt.Id
    LEFT JOIN (
        SELECT cliterm.ContractLineItem_id
            ,to_char(cliterm.Quantity) as Quantity
            ,cliterm.UsedQuantity
            ,cliterm.StartDate
        FROM ContractLineItemTerm cliterm
        WHERE cliterm.PriceRuleItem_id IS NULL
            AND (
                cliterm.EndDate IS NULL
                OR cliterm.EndDate > add_months(sysdate, - 3)
                )
        QUALIFY row_numumber() OVER (PARTITION BY cliterm.ContractLineItem_id ORDER BY cliterm.is_best ) = 1
    ) as bpi
        ON cli.id = bpi.ContractLineItem_id
    LEFT JOIN account acc 
        ON cust.SAN = acc.acc__c
    LEFT JOIN account acc1 
        ON acc.parentid = acc1.id
    LEFT JOIN sbSCRIPTION sb 
        ON sb.id = cli.sforceid
    LEFT JOIN sbSCRIPTION pasb 
        ON pasb.id = sb.srequired
    LEFT JOIN scontract1 cntr 
        ON cntr.contractnumber = con.ContNumber
    LEFT JOIN user accowner 
        ON acc.ownerid = accowner.id
    LEFT JOIN user accsalesmanager 
        ON accowner.managerid = accsalesmanager.id
    LEFT JOIN (
        SELECT f.accountid
            ,g.managerid
            ,max(g.NAME) CSM
            ,max(g.id) CSMID
        FROM accountteammember f
        JOIN user g ON f.userid = g.id
        WHERE f.teammemberrole = 'AGM'
        GROUP BY f.accountid
            ,g.managerid
        ) acccsm ON acccsm.accountid = acc.id
    LEFT JOIN product2 prd 
        ON prod.Code = prd.productcode
    LEFT JOIN prdfam prod_fam 
        ON prod_fam.product_family_desc = prd.Product_Family__c
    QUALIFY Quantity_Purchased <> 0;
    

    【讨论】:

      猜你喜欢
      • 2016-09-18
      • 1970-01-01
      • 2017-09-14
      • 1970-01-01
      • 2019-03-01
      • 2015-09-16
      • 2022-01-13
      • 2018-09-16
      • 2010-10-16
      相关资源
      最近更新 更多