【问题标题】:Parametizing query for ExcelExcel的参数化查询
【发布时间】:2020-06-15 07:49:29
【问题描述】:

更新:

我已经设法让以下查询与 Excel 一起使用:

SELECT me.id ,me.merchant_num ,me.merchant_nm,
CASE WHEN me.status = 'A' THEN 'Yes' ELSE 'No' END AS production_mode,
Max(CASE WHEN tt.bank_txt = 'IBA' THEN tt.transaction_dt END) AS last_IBA_transaction_dt,
convert(bit, Substring(Max(convert(CHAR(8), tt.transaction_dt, 112) + convert(CHAR(1), trans_live)), 9, 1)) AS is_live
FROM Data.dbo.merchant_t me
LEFT JOIN Data.dbo.transaction_t AS tt
  ON tt.merchant_id = me.id 
where tt.transaction_dt >= ?
and tt.transaction_dt <= ?
and tt.trans_status = ? 
GROUP BY me.id,me.merchant_num,me.merchant_nm, me.status

这个查询非常接近。我需要做的就是添加和删除如下查询 cmets 中所示的行:

SELECT me.id ,me.merchant_num ,me.merchant_nm,
    Count(CASE WHEN tt.transaction_dt >= ? 
               AND tt.transaction_dt <= ? 
               THEN tt.id end) AS num_transactions -- ADD THIS COUNT(CASE) STATEMENT
    CASE WHEN me.status = 'A' THEN 'Yes' ELSE 'No' END AS production_mode,
    Max(CASE WHEN tt.bank_txt = 'IBA' THEN tt.transaction_dt END) AS last_IBA_transaction_dt,
    convert(bit, Substring(Max(convert(CHAR(8), tt.transaction_dt, 112) + convert(CHAR(1), trans_live)), 9, 1)) AS is_live
    FROM Data.dbo.merchant_t me
    LEFT JOIN Data.dbo.transaction_t AS tt
      ON tt.merchant_id = me.id 
    where tt.transaction_dt >= ? -- REMOVE THIS LINE
    and tt.transaction_dt <= ? -- REMOVE THIS LINE
    and tt.trans_status = ? 
    GROUP BY me.id,me.merchant_num,me.merchant_nm, me.status

如果我将日期保留在以下行中,则查询适用于 Excel:

Count(CASE WHEN tt.transaction_dt >= '2020-04-01' AND tt.transaction_dt <= '2020-04-30' THEN tt.id end) AS num_transactions

而不是将它们参数化为

Count(CASE WHEN tt.transaction_dt >= ? AND tt.transaction_dt <= ? THEN tt.id end) AS num_transactions

如果我参数化它们,我会得到错误:

"Syntax error or access violation"

显然,我需要以某种方式参数化这些日期。

结束更新


我有一个 SQL 服务器查询如下:

WITH CTE_Merchants AS
(
    SELECT
        me.id, me.merchant_num, me.merchant_nm,
        COUNT(tt.id) as num_transactions,
        CASE 
           WHEN me.status = 'A' THEN 'Yes' 
           ELSE 'No' 
        END AS production_mode
    FROM
        merchant_t me
    LEFT OUTER JOIN 
        transaction_t tt ON tt.merchant_id = me.id 
                         AND tt.transaction_dt BETWEEN '2020-04-01' AND '2020-04-30' -- [PARAMETIZE BOTH DATES]
    WHERE 
        me.status = 'T' -- [PARAMETIZE]
    GROUP BY 
        me.id, me.merchant_num, me.merchant_nm, me.status
)
SELECT
    CTE_Merchants.id,
    CTE_Merchants.merchant_num,
    CTE_Merchants.merchant_nm,
    CTE_Merchants.num_transactions,
    CTE_Merchants.production_mode,
    A1.is_live,
    A2.last_IBA_transaction_dt
FROM
    CTE_Merchants
OUTER APPLY
    (SELECT TOP 1 transaction_t.trans_live AS is_live
     FROM transaction_t
     WHERE transaction_t.merchant_id = CTE_Merchants.id
     ORDER BY transaction_dt DESC) AS A1
OUTER APPLY
    (SELECT TOP 1 transaction_t.transaction_dt AS last_IBA_transaction_dt
     FROM transaction_t
     WHERE transaction_t.merchant_id = CTE_Merchants.id
       AND transaction_t.bank_txt = 'IBA'
     ORDER BY transaction_dt DESC) AS A2;

我想在 Excel 电子表格中使用查询,并且需要对查询 cmets 中指示的变量进行参数化。

以下是Excel数据连接对话框:

问题是:当我尝试参数化变量时,例如改变

AND tt.transaction_dt BETWEEN '2020-04-01' and '2020-04-30'

AND tt.transaction_dt BETWEEN ? and ?

我收到一个错误

参数号无效

紧随其后

描述符索引无效

如果我将 BETWEEN 语句更改为

,也会发生同样的事情
AND (tt.transaction_dt >= ? and  tt.transaction_dt <= ?)

另外,我的“参数”按钮是灰色的。

我怀疑它与查询本身有关,可能是因为参数隐藏在子查询中。我对此知之甚少。任何关于如何使其工作的建议,无论如何都有效。我听说您可以创建视图并查询视图,但目前我对 SQL 和 Excel 的了解有限。

我已经尝试过这个解决方案但没有成功:SQL Sub-query parameters from Excel

编辑

我刚刚从以下问题尝试了 behonji 的建议: How to add parameters to an external data query in Excel which can't be displayed graphically?

这里我在Excel中成功创建了一个参数化查询,如下:

SELECT merchant_t.id
FROM XXX.dbo.merchant_t merchant_t
where start_dt = ?
and create_dt = ?
and status = ?

然后,我用我的实际查询替换了该查询,我将其参数化如下:

WITH
CTE_Merchants
AS
(
    SELECT distinct
        me.id, me.merchant_num, me.merchant_nm
        ,count(tt.id) as num_transactions
        ,CASE WHEN me.status = 'A' THEN 'Yes' ELSE 'No' END as production_mode
    FROM
        merchant_t me
        LEFT OUTER JOIN transaction_t tt
            ON  tt.merchant_id = me.id 
            AND (tt.transaction_dt >= ? and tt.transaction_dt <= ?)
    WHERE me.status = ?
    GROUP BY me.id, me.merchant_num, me.merchant_nm, me.status
)
SELECT
    CTE_Merchants.id
    ,CTE_Merchants.merchant_num
    ,CTE_Merchants.merchant_nm
    ,CTE_Merchants.num_transactions
    ,CTE_Merchants.production_mode
    ,A1.is_live
    ,A2.last_IBA_transaction_dt
FROM
    CTE_Merchants
    OUTER APPLY
    (
        select top 1
            transaction_t.trans_live AS is_live
        from transaction_t
        where
            transaction_t.merchant_id = CTE_Merchants.id
        order by transaction_dt desc
    ) AS A1
    OUTER APPLY
    (
        select top 1
            transaction_t.transaction_dt AS last_IBA_transaction_dt
        from transaction_t
        where
            transaction_t.merchant_id = CTE_Merchants.id
            and transaction_t.bank_txt = 'IBA'
        order by transaction_dt desc
    ) AS A2
;

我得到与以前完全相同的错误。

【问题讨论】:

标签: sql-server excel


【解决方案1】:

我对 Excel 以及如何从 Excel 运行查询一无所知,但作为最后的手段,您可以尝试将复杂的查询包装到存储过程或表值函数中,然后从 Excel 中调用它。像下面的东西。

此外,最好有一个明确定义的数据库接口(以过程/函数的形式),即使您在技术上可以将复杂的查询直接放入 Excel 电子表格。如果需要,它将更容易维护您的代码和配置权限。 (您可以授予您的 Excel 用户仅执行此存储过程而不执行其他任何操作的权限,这样他们就不会弄乱数据库。)

存储过程

CREATE PROCEDURE [dbo].[ReadMerchants]
    @ParamStartDate date,
    @ParamEndDate date,
    @ParamStatus nvarchar(10)
AS
BEGIN
    SET NOCOUNT ON;

    -- Your query using the stored procedure parameters
    SELECT
    ...
    ;

END

这就是您从 Excel 中调用它的方式。

EXEC [dbo].[ReadMerchants]
    @ParamStartDate = ?,
    @ParamEndDate = ?,
    @ParamStatus = ?

表值函数

CREATE FUNCTION [dbo].[GetMerchants]
(
    @ParamStartDate date,
    @ParamEndDate date,
    @ParamStatus nvarchar(10)
)
RETURNS TABLE
AS
RETURN 
(
    -- Add the SELECT statement with parameter references here
    SELECT
    ...

)

这就是您从 Excel 中调用它的方式。

SELECT * FROM [dbo].[GetMerchants](?, ?, ?)

(显然,最好明确列出所有列,而不是键入*。)


如果存储过程和表值函数都适用于 Excel,我个人会使用存储过程 - 如果需要,您可以将任何类型的复杂逻辑放入其中。功能比较有限。

【讨论】:

    【解决方案2】:

    请尝试像这样编辑您的查询

    declare @dateFrom datetime = ?
    declare @dateTo datetime = ?
    declare @status varchar(20) = ?
    
    WITH
    CTE_Merchants
    AS
    (
        SELECT distinct
            me.id, me.merchant_num, me.merchant_nm
            ,count(tt.id) as num_transactions
            ,CASE WHEN me.status = 'A' THEN 'Yes' ELSE 'No' END as production_mode
        FROM
            merchant_t me
            LEFT OUTER JOIN transaction_t tt
                ON  tt.merchant_id = me.id 
                AND (tt.transaction_dt >= @dateFrom and tt.transaction_dt <= @dateTo)
        WHERE me.status = @status
        GROUP BY me.id, me.merchant_num, me.merchant_nm, me.status
    )
    SELECT
        CTE_Merchants.id
        ,CTE_Merchants.merchant_num
        ,CTE_Merchants.merchant_nm
        ,CTE_Merchants.num_transactions
        ,CTE_Merchants.production_mode
        ,A1.is_live
        ,A2.last_IBA_transaction_dt
    FROM
        CTE_Merchants
        OUTER APPLY
        (
            select top 1
                transaction_t.trans_live AS is_live
            from transaction_t
            where
                transaction_t.merchant_id = CTE_Merchants.id
            order by transaction_dt desc
        ) AS A1
        OUTER APPLY
        (
            select top 1
                transaction_t.transaction_dt AS last_IBA_transaction_dt
            from transaction_t
            where
                transaction_t.merchant_id = CTE_Merchants.id
                and transaction_t.bank_txt = 'IBA'
            order by transaction_dt desc
        ) AS A2
    ;
    

    【讨论】:

    • WITH 关键字前面必须有分号。
    猜你喜欢
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 2017-08-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多