简体   繁体   中英

Use date in Excel cell in BETWEEN clause in SQL query

(1) Table DB-Fiddle

CREATE TABLE logistics (
    id int primary key,
    Product VARCHAR(255),
    insert_timestamp Date
);

INSERT INTO logistics
(id, product, insert_timestamp
)
VALUES 
("1", "Product_A", "2020-02-24 18:15:48"),
("2", "Product_B", "2020-02-24 20:30:17"),
("3", "Product_C", "2020-02-24 23:54:58"),
("4", "Product_D", "2020-02-25 08:09:30"),
("5", "Product_E", "2020-02-25 10:17:15");

(2) VBA
Value in Cell B1 = 2020-02-24

Sub Get_Data()

Dim conn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim dateVar As Date

    Set conn = New ADODB.Connection
    conn.ConnectionString = "DRIVER={MySQL ODBC 5.1 Driver}; SERVER=localhost; DATABASE=bi; UID=username; PWD=password; OPTION=3"
    conn.Open

                strSQL = " SELECT " & _
                            " cID " & _
                            " FROM logistics " & _
                            " WHERE DATE(insert_timestamp) BETWEEN """ & Format(Sheet1.Range("B1").Value, "YYYY-MM-DD") & "00:00:00" & """ " & _
                            " AND """ & Format(Sheet1.Range("B1").Value, "YYYY-MM-DD") & "23:59:59" & """ " & _
                            " GROUP BY 1 "


    Set rs = New ADODB.Recordset
    rs.Open strSQL, conn, adOpenStatic

    Sheet1.Range("A1").CopyFromRecordset rs

    rs.Close
    conn.Close

End Sub

I want to run a query within the VBA that uses the date in Cell B1 within the BETWEEN statement in the WHERE clause.
When I run this query outside of the VBA it works perfectly:

SELECT
Product
FROM logistics
WHERE DATE(insert_timestamp) BETWEEN "2020-02-24 00:00:00" AND "2020-02-24 23:59:59";

Once, I run it in the VBA it does not give me an error but it also does not give me any result.
I assume the issue is caused by my combination of the sql and the VBA in the strSQL .

How do I have to change the VBA to make it work?

Instead of formatting values like dates or strings into the SQL command, it is much better to use ADODB.Parameter - in that case the driver will do all the work for you. You don't have to take care about quotes around a string, formatting a date so that the database understands it correctly (which is highly depending on database, regional settings and so on). Plus it is a protection against SQL injection. Plus, the query optimizer can do it's job much better because it gets the same SQL command every time and remembers the execution plan.

Drawback: code get's slightly more complicated because you have to involve a ADODB.command object.

In your SQL statement, you put a simple ? at the place where you want to have a parameter. You just have to take care that the numbers and the position of ? and parameters matches.

Dim Conn As New ADODB.Connection, cmd As New ADODB.Command, param As ADODB.Parameter, rs As ADODB.Recordset
Conn.Open "<your connection string>"
Set cmd.ActiveConnection = Conn
cmd.CommandText = "SELECT cID FROM logistics WHERE DATE(insert_timestamp) BETWEEN ? AND ? GROUP BY 1"

Set param = cmd.CreateParameter(, adDate, adParamInput, , Date)
cmd.Parameters.Append param
Set param = cmd.CreateParameter(, adDate, adParamInput, , Date + 1)
cmd.Parameters.Append param

Set rs = cmd.Execute
Debug.Print rs.Fields(0).Name, rs(0).Value

PS Was a little lazy for the date handling, if you have data exactly at midnight, you would get too much data.

you are missing a space between the date and the time...

Open your VBE and debug print the formula to see the result (maker sure you have the immediate window [view menu / Immediate window).

Sub test()
   Debug.Print Format(Sheet1.Range("B1").Value, "YYYY-MM-DD") & "23:59:59"
End Sub

result 2020-03-1123:59:59

Just can add the space after the DD as follow

Format(Sheet1.Range("B1").Value, "YYYY-MM-DD ") & "23:59:59"

I know you've accepted an answer and it's a perfectly good one. I'm just leaving this here as an alternative method which you might find useful in other cases too:

Dim date_to_use As String

date_to_use = Format(Sheet1.Range("B1").Value, "YYYY-MM-DD")

strSQl = " SELECT " & _
            " cID " & _
            " FROM logistics " & _
            " WHERE DATE(insert_timestamp) BETWEEN '[date to use] 00:00:00'" & _
            " AND '[date to use] 23:59:59'" & _
            " GROUP BY 1 "

strSQl = Replace(strSQl, "[date to use]", date_to_use)

Storing the contents of B1 in this way before using it also allows you to apply other changes to it - just in case you wanted to clean it up further or reduce the chances of SQL injection being used..

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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