简体   繁体   English

通过 Excel 数据“日期范围”到 SQL 查询

[英]Pass Excel Data "Date Range" to SQL Query

I have a large 115 line SQL code that I have been tasked to put into Excel and allow the user with two cells to change the date range of the SQL code and show the results.我有一个大的 115 行 SQL 代码,我的任务是放入 Excel 并允许具有两个单元格的用户更改 Z9778840A0100CB30C9822876741B05B 代码的日期范围I have tried several of the other topics with no luck.我已经尝试了其他几个主题,但没有成功。 I am using Microsoft 365. Each user has a ODBC connection on their PC named "Reports55" In excel I have two tabs (Summary) and (SQLData).我正在使用 Microsoft 365。每个用户在其 PC 上都有一个名为“Reports55”的 ODBC 连接。在 excel 中,我有两个选项卡(摘要)和(SQLData)。 on the (Summary) tab Cell A2 is the 1StartDate and Cell B2 is the 2EndDate.在(摘要)选项卡上,单元格 A2 是 1StartDate,单元格 B2 是 2EndDate。 The (SQLDate) tab is where the SQL Query data will be shown. (SQLDate) 选项卡将显示 SQL 查询数据。 Any help will be greatly appreciated.任何帮助将不胜感激。

Skill level技能等级

  • VBA: Beginner (Please dumb it down for this old guy) VBA:初学者(请给这个老家伙哑巴)
  • SQL: Intermediate SQL:中级
  • Excel: Intermediate Excel:中级
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')

Consider the following steps for parameterized querying:考虑参数化查询的以下步骤:

SQL SQL

  1. Keep your long, intricate SQL in an .sql text file.将长而复杂的 SQL 保存在.sql文本文件中。 Format with line breaks and indentation any way you need.以您需要的任何方式使用换行符和缩进进行格式化。 Keep in same folder as workbook or centralized location for all users to read in VBA.保存在与工作簿相同的文件夹或集中位置,供所有用户在 VBA 中阅读。

  2. Remove DECLARE and SET lines, keeping only the single SELECT command.删除DECLARESET行,仅保留单个SELECT命令。

  3. In SELECT query replace every @ variable with qmarks ?SELECT查询中用 qmarks 替换每个@变量? for parameterization in VBA.用于 VBA 中的参数化。

     WHERE SO_Detail.Shpdte_28 BETWEEN? AND?

VBA VBA

  1. Start a VBA Sub subroutine in Workbooks module or standalone module.在 Workbooks 模块或独立模块中启动 VBA Sub例程。

  2. Set up an ADO ODBC connection to your database.设置与数据库的 ADO ODBC 连接。 Many online examples and tutorials.许多在线示例和教程。

  3. Read in SQL query into a string variable:将 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
  4. Open an ADO Command object using connection object and query.使用连接 object 打开 ADO 命令 object 并查询。 Create and bind the two date parameters from wherever cells they are located in workbook.从它们位于工作簿中的任何单元格创建并绑定两个日期参数。 Then execute command to render an ADO recordset.然后执行命令来呈现一个 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
  5. Use Range.CopyFromRecordset to output recordset to sheet starting at left most column.使用Range.CopyFromRecordset到 output 记录集到从最左侧列开始的工作表。 Do note: columns do not populate.请注意:不填充列。 Loop through recordset Fields for such column names.循环遍历此类列名的记录集Fields

     ThisWorkbook.Worksheets("SQLData").Range("A2").CopyFromRecordset rs

(In entire VBA code, be sure to specify Dim variables with Option Explicit at very top and incorporate proper error handling that closes recordset and connection and release ASO resources by setting objects to Nothing with or without runtime errors.) (在整个 VBA 代码中,请务必在最顶部使用Option Explicit指定Dim变量,并结合适当的错误处理,通过将对象设置为Nothing (有或没有运行时错误)来关闭记录集和连接并释放 ASO 资源。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM