[英]Pass Excel Data "Date Range" to SQL Query
我有一个大的 115 行 SQL 代码,我的任务是放入 Excel 并允许具有两个单元格的用户更改 Z9778840A0100CB30C9822876741B05B 代码的日期范围我已经尝试了其他几个主题,但没有成功。 我正在使用 Microsoft 365。每个用户在其 PC 上都有一个名为“Reports55”的 ODBC 连接。在 excel 中,我有两个选项卡(摘要)和(SQLData)。 在(摘要)选项卡上,单元格 A2 是 1StartDate,单元格 B2 是 2EndDate。 (SQLDate) 选项卡将显示 SQL 查询数据。 任何帮助将不胜感激。
技能等级
DECLARE @1StartDate AS DATE
DECLARE @2EndDate AS DATE
SET @1StartDate = '2020-04-27'
SET @2EndDate = '2021-05-27'
SELECT
'SHIP' AS RPT ,
SO_Detail_Ext.LateReason ,
(SO_Detail.ordnum_28 + SO_Detail.linnum_28 + SO_Detail.delnum_28) AS "Order",
SO_Detail.custid_28 AS "CustID",
SO_Detail.Prtnum_28 AS "Part",
CONVERT(VARCHAR(10), SO_Master.ORDDTE_27, 101) AS "OrdDte",
CONVERT(VARCHAR(10), SO_Detail.Shpdte_28, 101) AS "Shpdte",
ExactMAX.dbo.NumShopDays(SO_Master.ORDDTE_27,SO_Detail.shpdte_28) AS "LT_ToShip",
CONVERT(VARCHAR(10), SO_Detail.ORGDUE_28, 101) AS "OrgDue" ,
CONVERT(VARCHAR(10), SO_Detail.Curdue_28, 101) AS "Curdue_PDSL",
CONVERT(VARCHAR(10), SO_Detail.CUSDUE_28, 101) AS "Custdue_RDSL",
SO_Detail.Price_28 AS "Price",
SO_Detail.Shpqty_28 AS "ShpQty",
Customer_Master.udfkey_23 AS "UDFKey",
Customer_Master.Slster_23 AS "Territory",
Account_Types.DESCRPTN_104 AS "AccType",
Customer_Master.SLSTER_23 AS "WordArea" , --'Undefined World Area'
Customer_Master_Ext.CustomerClass ,
(SO_Detail.Price_28 * SO_Detail.Shpqty_28) AS "Extended",
CAST('1' AS INTEGER) AS "Shipped",
CASE WHEN SO_Detail.Shpdte_28 <= SO_Detail.Curdue_28 THEN 1 ELSE 0 END AS "PDSL_OnTime",
CASE
WHEN SO_Detail_Ext.LateReason = 'SSI' THEN '1' --Customer caused late order
WHEN SO_Detail.shpdte_28 <= SO_Detail.Cusdue_28 THEN 1 ELSE 0 END AS "RDSL_OnTime",
CASE WHEN Customer_Master_Ext.CustomerClass = 'TRADE'
THEN 1 ELSE 0 END AS "Trade_Shipped", --01 Total Trade Lines Shipped
CASE WHEN SO_Detail.Shpdte_28 <= SO_Detail.Curdue_28
AND Customer_Master_Ext.CustomerClass = 'TRADE' THEN 1 ELSE 0 END AS "Trade_Ontime_PDSL",
CASE WHEN SO_Detail.Shpdte_28 <= SO_Detail.CUSDUE_28
AND Customer_Master_Ext.CustomerClass = 'TRADE' THEN 1 ELSE 0 END AS "Trade_Ontime_RDSL",
CASE WHEN Customer_Master_Ext.CustomerClass = 'TRADE'
AND isnull(Part_Master_Ext.ExpressShip, 0) = '1' THEN 1 ELSE 0 END AS "Trade_Exp_Shipped",
CASE WHEN SO_Detail.Shpdte_28 <= SO_Detail.CUSDUE_28
AND Customer_Master_Ext.CustomerClass = 'TRADE'
AND isnull(Part_Master_Ext.ExpressShip, 0) = '1' THEN 1 ELSE 0 END AS "Trade_EXP_Ontime_RDSL",
CASE WHEN SO_Detail.Shpdte_28 <= SO_Detail.Curdue_28
AND Customer_Master_Ext.CustomerClass = 'TRADE'
AND isnull(Part_Master_Ext.ExpressShip, 0) = '1' THEN 1 ELSE 0 END AS "Trade_EXP_Ontime_PDSL",
CASE WHEN Customer_Master_Ext.CustomerClass = 'TRADE'
AND isnull(Part_Master_Ext.ExpressShip, 0) <> '1' THEN 1 ELSE 0 END AS "Trade_MTO_Shipped",
CASE WHEN SO_Detail.Shpdte_28 <= SO_Detail.CUSDUE_28
AND Customer_Master_Ext.CustomerClass = 'TRADE'
AND isnull(Part_Master_Ext.ExpressShip, 0) <> '1' THEN 1 ELSE 0 END AS "Trade_MTO_Ontime_RDSL",
CASE WHEN SO_Detail.Shpdte_28 <= SO_Detail.Curdue_28
AND Customer_Master_Ext.CustomerClass = 'TRADE'
AND isnull(Part_Master_Ext.ExpressShip, 0) <> '1' THEN 1 ELSE 0 END AS "Trade_MTO_Ontime_PDSL",
CASE WHEN Customer_Master_Ext.CustomerClass IN ('INTERCO', 'INTRA-CO')
THEN 1 ELSE 0 END AS "Intraco_Shipped", -- 03 Intraco Lines Shipped
CASE WHEN SO_Detail.Shpdte_28 <= SO_Detail.Curdue_28
AND Customer_Master_Ext.CustomerClass IN ('INTERCO', 'INTRA-CO')
THEN 1 ELSE 0 END AS "Intraco_OnTime_PDSL",
CASE
WHEN SO_Detail_Ext.LateReason = 'SSI' AND Customer_Master_Ext.CustomerClass IN ('INTERCO', 'INTRA-CO') THEN '1' --Customer caused late order
WHEN SO_Detail.Shpdte_28 <= SO_Detail.CUSDUE_28
AND Customer_Master_Ext.CustomerClass IN ('INTERCO', 'INTRA-CO')
THEN 1 ELSE 0 END AS "Intraco_Ontime_RDSL",
CASE WHEN isnull(Part_Master_Ext.ExpressShip, 0) = '1'
THEN 1 ELSE 0 END AS "EXP_Shipped",
CASE WHEN SO_Detail.Shpdte_28 <= SO_Detail.CURDUE_28
AND isnull(Part_Master_Ext.ExpressShip, 0) = '1' THEN 1 ELSE 0 END AS "EXP_Ontime_PDSL",
CASE
WHEN SO_Detail_Ext.LateReason = 'SSI' AND isnull(Part_Master_Ext.ExpressShip, 0) = '1' THEN '1'
WHEN SO_Detail.Shpdte_28 <= SO_Detail.CUSDUE_28
AND isnull(Part_Master_Ext.ExpressShip, 0) = '1' THEN 1 ELSE 0 END AS "EXP_Ontime_RDSL" ,
ExactMAX.dbo.NumShopDays(SO_Master.ORDDTE_27,SO_Detail.shpdte_28) AS "AVG_LT_Days" ,
ExactMAX.dbo.NumShopDays(SO_Master.ORDDTE_27,SO_Detail.Cusdue_28) AS "RDSL_AVG_LT_Days" ,
ExactMAX.dbo.NumShopDays(SO_Master.ORDDTE_27,SO_Detail.Curdue_28) AS "PDSL_AVG_LT_Days" ,
CASE WHEN Customer_Master_Ext.CustomerClass = 'TRADE'
AND isnull(Part_Master_Ext.ExpressShip, 0) <> '1'
THEN ExactMAX.dbo.NumShopDays(SO_Master.ORDDTE_27,SO_Detail.shpdte_28)
ELSE NULL END AS "Trade_MTO_AVGLT" ,
CASE WHEN Customer_Master_Ext.CustomerClass IN ('INTERCO', 'INTRA-CO')
THEN ExactMAX.dbo.NumShopDays(SO_Master.ORDDTE_27,SO_Detail.shpdte_28)
ELSE NULL END AS "Intraco_AVG_LT" ,
CAST('0' AS FLOAT) AS "Trade_Backlog_PDSL" , --09 Trade $$ Past Due Backlog by PDSL
CAST('0' AS FLOAT) AS "Trade_Backlog_RDSL" , --10 Trade $$ Past Due Backlog by RDSL
CASE WHEN Customer_Master_Ext.CustomerClass = 'TRADE'
THEN (SO_Detail.Price_28 * SO_Detail.Shpqty_28)
ELSE NULL
END AS "Trade_Sales$$" ,
NULL AS "Total_PastDue_Dollars_RDSL" ,
NULL AS "Total_PastDue_Lines_RDSL" ,
NULL AS "Total_PastDue_Dollars_PDSL" ,
NULL AS "Total_PastDue_Lines_PDSL" ,
SO_Detail.CreatedBy ,
SO_Detail.CreationDate ,
Part_Sales.CRTLTO_29
FROM
ExactMAX.dbo.SO_Detail LEFT JOIN
ExactMAX.dbo.Part_Sales ON
SO_Detail.PRTNUM_28 = Part_Sales.PRTNUM_29 LEFT JOIN
ExactMAX.dbo.SO_Master ON
SO_Detail.ORDNUM_28=SO_Master.ORDNUM_27 LEFT JOIN
ExactMAX.dbo.part_Master ON
SO_Detail.prtnum_28 = part_master.prtnum_01 LEFT JOIN
ExactMAX.dbo.Account_Types ON
Part_Master.ACTTYP_01=Account_Types.ACTTYP_104 LEFT JOIN
ExactMAX.dbo.CUSTOMER_MASTER ON
SO_Detail.CUSTID_28 = CUSTOMER_MASTER.CUSTID_23 LEFT JOIN
ExactMAX.dbo.Part_Master_Ext ON
SO_Detail.prtnum_28 = part_master_ext.prtnum_01 LEFT JOIN
ExactMAX.dbo.Customer_Master_Ext ON
Customer_Master.CUSTID_23 = Customer_Master_Ext.CUSTID_23 LEFT JOIN
ExactMAX.dbo.SO_Detail_Ext ON
SO_Detail_ext.ORDER_LIN_DEL = (SO_Detail.ORDNUM_28 + SO_Detail.LINNUM_28 + SO_Detail.DELNUM_28)
WHERE
SO_Detail.Shpdte_28 BETWEEN @1StartDate AND @2EndDate
AND SO_Detail.Status_28 IN ('4', '5')
AND Part_Master.Acttyp_01 <> ''
AND Part_Master.TYPE_01 IN ('A', 'C', 'P', 'S', 'X')
考虑参数化查询的以下步骤:
SQL
将长而复杂的 SQL 保存在.sql
文本文件中。 以您需要的任何方式使用换行符和缩进进行格式化。 保存在与工作簿相同的文件夹或集中位置,供所有用户在 VBA 中阅读。
删除DECLARE
和SET
行,仅保留单个SELECT
命令。
在SELECT
查询中用 qmarks 替换每个@
变量?
用于 VBA 中的参数化。
WHERE SO_Detail.Shpdte_28 BETWEEN? AND?
VBA
在 Workbooks 模块或独立模块中启动 VBA Sub
例程。
设置与数据库的 ADO ODBC 连接。 许多在线示例和教程。
将 SQL 查询读入字符串变量:
' READ SQL QUERY FROM FILE INTO STRING With CreateObject("Scripting.FileSystemObject") strSQL =.OpenTextFile("C:\path\to\my\SQL\Query.sql", 1).readall End With
使用连接 object 打开 ADO 命令 object 并查询。 从它们位于工作簿中的任何单元格创建并绑定两个日期参数。 然后执行命令来呈现一个 ADO 记录集。
' DEFINE COMMAND OBJECT Set cmd = New ADODB.Command With cmd.ActiveConnection = conn ' CONNECTION OBJECT.CommandType = adCmdText.CommandText = strSQL ' SQL QUERY ' BIND DATE PARAMETERS FOR? IN SQL, ASSUMING startDate AND endDate ARE VBA DATES.Parameters.Append.CreateParameter("dtparam1", adDate, adParamInput, , startDate).Parameters.Append.CreateParameter("dtparam2", adDate, adParamInput, , endDate) ' BIND OUTPUT TO RECORDSET Set rs =.Execute End With
使用Range.CopyFromRecordset到 output 记录集到从最左侧列开始的工作表。 请注意:不填充列。 循环遍历此类列名的记录集Fields
。
ThisWorkbook.Worksheets("SQLData").Range("A2").CopyFromRecordset rs
(在整个 VBA 代码中,请务必在最顶部使用Option Explicit
指定Dim
变量,并结合适当的错误处理,通过将对象设置为Nothing
(有或没有运行时错误)来关闭记录集和连接并释放 ASO 资源。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.