【问题标题】:Suitescript SuiteQL Error with IN operator带有 IN 运算符的 Suitescript SuiteQL 错误
【发布时间】:2021-08-30 06:01:30
【问题描述】:

SuiteQL

SELECT *
    FROM   transactionline
    WHERE  ( transactionline.department, transactionline.cseg_grant ) IN (( '11',
           '1' ))

上面的查询当使用suiteQL运行时,它返回下面的error

错误:

Search error occurred: Invalid or unsupported search

这是ORACLE 中的有效语法我在Oracle 中尝试了一个示例查询,执行过程中没有问题,而此语法在SuiteQL 中不起作用

【问题讨论】:

  • 因为每个数据库引擎都是不同的。改写成WHERE transactionline.department = 11 and transactionline.cseg_grant = 1
  • 谢谢@juergend,你是对的。这会起作用,但是当有更多组时,我正在寻找一种改进的方式来编写查询,例如:( transactionline.department, transactionline.cseg_grant ) IN (( '11', '1' ), ('12', ''.2), .....)。分别保留所有不同的条件将使查询非常冗长。也可能有更多的列,例如:( transactionline.department, transactionline.cseg_grant, transactionline.class, ...... )

标签: sql netsuite suitescript suitescript2.0 suiteql


【解决方案1】:

我们的解决方案是创建一个可以通过 query.runSuiteQL() 执行 SQL 的 RESTlet。我相信您遇到的问题是由于本机 Web 服务提供了分页响应 - 并且没有限制和偏移参数调用 /query/v1/suiteql 端点并不能解决问题。

您可以自己确认/尝试:通过 query.runSuiteQL() 测试您的 SQL,您将获得结果,但通过 query.runSuiteQLPaged() 使用相同的 SQL,您将收到错误消息“无效或不受支持”搜索”。

我认为使用 query.runSuiteQL() 有 5000 条记录的限制。

这是 RESTlet 的 JS 代码:

/**
 * @NApiVersion 2.1
 * @NScriptType Restlet
 * @NModuleScope SameAccount

Name:
UH SuiteQL API

ID:
_uh_suiteql_api_restlet

Description:
A RESTlet that serves as an RPC-style API for SuiteQL.

Developers:
Tim Dietrich
Simeon Bartley

*/
define(["require", "exports", "N/query", "N/error", "N/log"], function (require, exports, query, error, log) {
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.throwError = exports.post = void 0;
    const post = async (requestParameters) => {
        try {
            if (typeof requestParameters.function === "undefined" || requestParameters.function === "") {
                throwError("No function was specified.");
            }
            switch (requestParameters.function) {
                case "sqlRunUnpaged":
                    return JSON.stringify(await sqlRunUnpaged(requestParameters));
                case "sqlRunPaged":
                    return JSON.stringify(await sqlRunPaged(requestParameters));
                default:
                    throwError("Unsupported function.");
            }
        }
        catch (e) {
            return JSON.stringify({ "error": e.message });
        }
    };
    exports.post = post;
    function throwError(message, name = "") {
        const errorObj = error.create({ name, message, notifyOff: false });
        log.error({ title: "", details: errorObj });
        throw new Error(errorObj.message);
    }
    exports.throwError = throwError;
    /** Unpaged queries will return up to 5000 records. */
    async function sqlRunUnpaged(requestParameters) {
        if (typeof requestParameters.sql === "undefined" || requestParameters.sql === "") {
            throwError("No SQL specified.");
        }
        try {
            const res = await query.runSuiteQL.promise({ query: requestParameters.sql });
            const records = res.asMappedResults();
            return {
                "items": records
            };
        }
        catch (e) {
            throwError(e.message);
        }
    }
    /** Paged query handler - useful where > 5000 records may be required, or subsets are desirable. */
    async function sqlRunPaged(requestParameters) {
        if (typeof requestParameters.sql === "undefined" || requestParameters.sql === "") {
            throwError("No SQL specified.");
        }
        const maxPageSize = 5000;
        let pageSize = typeof requestParameters.pageSize === "undefined" ? maxPageSize : Number.parseInt(requestParameters.pageSize.toString());
        if (pageSize < 0) {
            pageSize = maxPageSize;
        }
        let pageNumber = typeof requestParameters.pageNumber === "undefined" ? 1 : Number.parseInt(requestParameters.pageNumber.toString());
        if (pageNumber < 1) {
            pageNumber = 1;
        }
        try {
            const res = await query.runSuiteQLPaged.promise({ query: requestParameters.sql, pageSize: pageSize });
            let items = [];
            let hasMore = false;
            if (res.pageRanges.length > 0) {
                pageNumber = pageNumber <= res.pageRanges.length ? pageNumber : 1;
                const page = res.fetch(pageNumber - 1);
                items = page.data.asMappedResults();
                hasMore = !page.isLast;
            }
            return {
                "totalResults": res.count,
                "count": items.length,
                "offset": (pageNumber - 1) * res.pageSize,
                "hasMore": hasMore,
                "pageSize": res.pageSize,
                "pageNumber": pageNumber,
                "items": items
            };
        }
        catch (e) {
            throwError(e.message);
        }
    }
});

这个 RESTlet 改编自 Tim Dietrich 的工作。上面的 JS 是从 TypeScript 转译的(你需要@hitc/netsuite-types):

/**
 * @NApiVersion 2.1
 * @NScriptType Restlet
 * @NModuleScope SameAccount

Name:
UH SuiteQL API

ID:
_uh_suiteql_api_restlet

Description:
A RESTlet that serves as an RPC-style API for SuiteQL.

Developers:
Tim Dietrich
Simeon Bartley

*/

import { EntryPoints } from "N/types";
import * as query from "N/query";
import * as error from "N/error";
import * as log from "N/log";

interface IRouteBaseParameters {
    function?: string
}

interface ISuiteQLRunUnpagedParameters {
    sql?: string;
}

interface ISuiteQLRunPagedParameters {
    sql?: string;
    pageSize?: number;
    pageNumber?: number;
}

interface ISuiteQlUnpagedResultJson {
    items: unknown[];
}

interface ISuiteQlPagedResultJson {
    totalResults: number;
    count: number;
    offset: number;
    hasMore: boolean;
    pageSize: number,
    pageNumber: number,
    items: unknown[];
}

type IAllRequestParameters = IRouteBaseParameters & ISuiteQLRunUnpagedParameters & ISuiteQLRunPagedParameters;

export const post: EntryPoints.RESTlet.post = async (requestParameters: IAllRequestParameters): Promise<string> => {
    try {
        if (typeof requestParameters.function === "undefined" || requestParameters.function === "") {
            throwError("No function was specified.");
        }

        switch (requestParameters.function) {
            case "sqlRunUnpaged":
                return JSON.stringify(await sqlRunUnpaged(requestParameters));
            case "sqlRunPaged":
                return JSON.stringify(await sqlRunPaged(requestParameters));
            default:
                throwError("Unsupported function.");
        }
    }
    catch (e: unknown) {
        return JSON.stringify({ "error": (e as Error).message });
    }
}

export function throwError(message: string, name: string = ""): never {
    const errorObj = error.create({ name, message, notifyOff: false });
    log.error({ title: "", details: errorObj });
    throw new Error(errorObj.message);
}

/** Unpaged queries will return up to 5000 records. */
async function sqlRunUnpaged(requestParameters: ISuiteQLRunUnpagedParameters): Promise<ISuiteQlUnpagedResultJson> {
    if (typeof requestParameters.sql === "undefined" || requestParameters.sql === "") {
        throwError("No SQL specified.");
    }

    try {
        const res = await query.runSuiteQL.promise({ query: requestParameters.sql });
        const records = res.asMappedResults();
        return {
            "items": records
        };
    }
    catch (e: unknown) {
        throwError((e as Error).message);
    }
}

/** Paged query handler - useful where > 5000 records may be required, or subsets are desirable. */
async function sqlRunPaged(requestParameters: ISuiteQLRunPagedParameters): Promise<ISuiteQlPagedResultJson> {
    if (typeof requestParameters.sql === "undefined" || requestParameters.sql === "") {
        throwError("No SQL specified.");
    }

    const maxPageSize = 5000;

    let pageSize = typeof requestParameters.pageSize === "undefined" ? maxPageSize : Number.parseInt(requestParameters.pageSize.toString());
    if (pageSize < 0) {
        pageSize = maxPageSize;
    }

    let pageNumber = typeof requestParameters.pageNumber === "undefined" ? 1 : Number.parseInt(requestParameters.pageNumber.toString());
    if (pageNumber < 1) {
        pageNumber = 1;
    }

    try {
        const res = await query.runSuiteQLPaged.promise({ query: requestParameters.sql, pageSize: pageSize });
        let items: unknown[] = [];
        let hasMore = false;
        if (res.pageRanges.length > 0) {
            pageNumber = pageNumber <= res.pageRanges.length ? pageNumber : 1;
            const page = res.fetch(pageNumber - 1);
            items = page.data.asMappedResults();
            hasMore = !page.isLast;
        }

        return {
            "totalResults": res.count,
            "count": items.length,
            "offset": (pageNumber - 1) * res.pageSize,
            "hasMore": hasMore,
            "pageSize": res.pageSize,
            "pageNumber": pageNumber,
            "items": items
        };
    }
    catch (e: unknown) {
        throwError((e as Error).message);
    }
}

我希望原生 Web 服务会及时改进,从而使这种方法变得多余。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-17
    • 1970-01-01
    • 2021-05-11
    • 2015-05-05
    • 2012-07-11
    • 1970-01-01
    • 2019-06-27
    相关资源
    最近更新 更多