1

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

4

1 回答 1

0

我们的解决方案是创建一个可以通过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 服务会及时改进,从而使这种方法变得多余。

于 2022-03-02T01:50:22.400 回答