Where sql vba excel

I’m trying to write VBA code to get SQL data into Excel. Everything works fine except the WHERE condition. I think the problem may be with quotation. This is my query:

Sub Engineering_Milestone()

Dim v_project As String
Dim cn  As ADODB.Connection
Dim rs  As ADODB.Recordset
Dim sql As String

Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset

v_project = Worksheets("Parameters").Range("B1").Value

'cn.Open "Provider = x.1; Data Source=x; Initial Catalog=x; Integrated Security=x"


cn.Open "Provider = Sx; Data Source=x; Initial Catalog=x; Integrated Security=x"

Worksheets("Engineering_Milestone").Range("A2:G5000").ClearContents

sql = " SELECT A.ENGINEER_ID, B.[Description], B.BUDGET_APPROVED, A.MILESTONE, A.[DESCRIPTION], A.PCT_COMPLETE, A.SCHEDULE_DATE FROM X as A  Inner Join X as B on A.ENGINEER_ID = B.ENGINEER_ID WHERE B.Project_ID = " & "'" & v_project & "'" and A.Project_ID = " & "'" & v_project & "'"

rs.Open sql, cn

Sheets("Engineering_Milestone").Cells(2, 1).CopyFromRecordset rs

rs.Close
cn.Close

End Sub

It works fine when the SQL query has one condition i.e …where B.Project_ID = " & "'" & v_project & "'" (without second condition -> and A.Project_ID = " & "'" & v_project & "'").

I’m very new to this so would be grateful if anyone can help…Many thanks.

Parfait's user avatar

Parfait

103k17 gold badges95 silver badges123 bronze badges

asked Aug 11, 2018 at 21:06

TAG's user avatar

3

As I said never write SQL code by string concatenation, use parameters. After seeing your code it is now a little bit easier:

Sub Engineering_Milestone()

Dim v_project As String
Dim cn  As ADODB.Connection
Dim rs  As ADODB.Recordset
Dim sql As String
Dim cmd as ADODB.Command

Set cn = New ADODB.Connection

v_project = Worksheets("Parameters").Range("B1").Value

'cn.Open "Provider = x.1; Data Source=x; Initial Catalog=x; Integrated Security=x"


cn.Open "Provider = Sx; Data Source=x; Initial Catalog=x; Integrated Security=x"

Worksheets("Engineering_Milestone").Range("A2:G5000").ClearContents

sql = "SELECT A.ENGINEER_ID, B.[Description], B.BUDGET_APPROVED, " & _
      "   A.MILESTONE, A.[DESCRIPTION], A.PCT_COMPLETE, A.SCHEDULE_DATE" & _
      " FROM X as A" & _
      " Inner Join X as B " & _
      "   on A.ENGINEER_ID = B.ENGINEER_ID and B.Project_ID = A.Project_ID" & _
      " WHERE B.Project_ID = ?"

  set cmd = New ADODB.Command
  cmd.ActiveConnection = cn
  cmd.CommandText = sql
  cmd.Parameters.Append cmd.CreateParameter("@projectId", adVarchar)
  cmd.Parameters("@projectId").Value = v_project

  Set rs = cmd.Execute()

  Sheets("Engineering_Milestone").Cells(2, 1).CopyFromRecordset rs

rs.Close
cn.Close

End Sub

NOTE: Your SQL is really vague. You are doing a self join just to create some kind of cartesian join? Probably in fact engineerId, projectId combinations are unique. If that is correct than you could simplify your SQL:

sql = "SELECT ENGINEER_ID, [Description], BUDGET_APPROVED, " & _
      "   MILESTONE, [DESCRIPTION], PCT_COMPLETE, SCHEDULE_DATE" & _
      " FROM X" & _
      " WHERE Project_ID = ?"

Parfait's user avatar

Parfait

103k17 gold badges95 silver badges123 bronze badges

answered Aug 12, 2018 at 12:25

Cetin Basoz's user avatar

Cetin BasozCetin Basoz

21.6k3 gold badges29 silver badges38 bronze badges

4

You only provided a half of one line of code so I’m can only guess that this is what you’re trying for:

"where B.Project_ID = '"& v_project &"'& And A.Project_ID = ' & v_project  "'"

Strings can be confusing when entering/exiting multiple types of quotes, but when you’re troubleshooting a problem building a string, start be remove all the variables and just using a hard-coded SQL string.

Once that’s working, start replacing the values with variables (and appropriate quotes) one at a time.

answered Aug 11, 2018 at 21:13

ashleedawg's user avatar

ashleedawgashleedawg

20k8 gold badges73 silver badges104 bronze badges

3

Consider SQL parameterization, the industry best practice when passing values into SQL queries -not just in VBA or your database but across all langauge interfaces to any databases. This process is more readable and maintainable as you no longer worry about quotes. Plus, code (SQL query) is separated from data (VBA variables).

Using ADO, parameters can be defined and set using the Command Object.

Dim v_project As String, sql As String
Dim cn  As New ADODB.Connection
Dim rs  As New ADODB.Recordset
Dim cmd As New ADODB.Command

v_project = Worksheets("Parameters").Range("B1").Value

cn.Open "Provider = Sx; Data Source=x; Initial Catalog=x; Integrated Security=x"

' PREPARED STATEMENT WITH QMARK PLACEHOLDERS
sql = "SELECT A.ENGINEER_ID, B.[Description], B.BUDGET_APPROVED, A.MILESTONE," _
       & "    A.[DESCRIPTION], A.PCT_COMPLETE, A.SCHEDULE_DATE" _
       & " FROM X AS A INNER JOIN X as B ON A.ENGINEER_ID = B.ENGINEER_ID" _
       & " WHERE B.Project_ID = ? AND A.Project_ID = ?"

' COMMAND OBJECT 
Set cmd = New ADODB.Connection

With cmd
    .ActiveConnection = cn    ' CONNECTION OBJECT
    .CommandText = sql
    .CommandType = adCmdText

    ' BINDING PARAMETERS
    .Parameters.Append .CreateParameter("a_projid", adVarChar, adParamInput, , v_project)
    .Parameters.Append .CreateParameter("b_projid", adVarChar, adParamInput, , v_project)
End With

' ASSIGN TO RECORDSET
Set rs = cmd.Execute

With Worksheets("Engineering_Milestone")
     .Range("A2:G5000").ClearContents
     .Cells(2, 1).CopyFromRecordset rs
End With

rs.Close: cn.Close
Set cmd = Nothing: Set rs = Nothing: Set cn = Nothing

answered Aug 12, 2018 at 1:52

Parfait's user avatar

ParfaitParfait

103k17 gold badges95 silver badges123 bronze badges

2

Never write SQL code like that concatenating strings. Instead simply use parameters. ie: (say vProject is integer)

.. where B.Project_ID = ? And A.Project_ID = ?

cmd.Parameters.Append .CreateParameter("@projectId", adInteger, adParamInput, 0, vProject)
cmd.Parameters.Append .CreateParameter("@projectId", adInteger, adParamInput, 0, vProject)

Note: cmd is your ADODB.Command object that you use for your command.

answered Aug 11, 2018 at 21:20

Cetin Basoz's user avatar

Cetin BasozCetin Basoz

21.6k3 gold badges29 silver badges38 bronze badges

3

Содержание

  • 1 Add where clause to the select statement
  • 2 Creating a Select Query with ActiveX Data Objects
  • 3 Executing a Select Query
  • 4 Get DISTINCT records
  • 5 Get DISTINCTROW
  • 6 Get more than one column
  • 7 Get only one column
  • 8 Get the top 10 percent
  • 9 Get the top 5 percent
  • 10 Loop through the ResultSet after executing select statement
  • 11 Modifying a Select Query
  • 12 Order by two fields
  • 13 Order record in a decscending order
  • 14 Order the resultset with Order by clause
  • 15 Select all columns
  • 16 Use and to combine conditions
  • 17 Use Between And
  • 18 Use between and with number type column
  • 19 Use Date function in where clause
  • 20 Use IN and like in where clause
  • 21 Use IN in select statement
  • 22 Use «Is not null»
  • 23 Use Is NULL to check if a column is null
  • 24 Use Not In
  • 25 Use «Select all»
  • 26 use SUM in sql statement
  • 27 Use where clause and order by clause together
  • 28 Use wild card character in link
  • 29 Using Date field type in select statement
  • 30 You must use a pound symbol (#) when delimiting dates for Microsoft Access, like this:

Add where clause to the select statement

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("SELECT txtCustFimyRecordsetName, txtCustLastName FROM tblCustomer WHERE txtState = "NJ"")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Creating a Select Query with ActiveX Data Objects

   <source lang="vb">

Sub Create_SelectQuery()

  Dim cat As ADOX.Catalog
  Dim cmd As ADODB.rumand
  Dim strPath As String
  Dim strSQL As String
  Dim strQryName As String
  On Error GoTo ErrorHandler
  strPath = CurrentProject.Path & "mydb.mdb"
  strSQL = "SELECT Employees.* FROM Employees WHERE Employees.City="London";"
  strQryName = "London Employees"
  Set cat = New ADOX.Catalog
  cat.ActiveConnection = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strPath
  Set cmd = New ADODB.rumand
  cmd.rumandText = strSQL
  cat.Views.Append strQryName, cmd

ExitHere:

  Set cmd = Nothing
  Set cat = Nothing
  MsgBox "The procedure completed successfully.", _
      vbInformation, "Create Select Query"
  Exit Sub

ErrorHandler:

  If InStr(Err.Description, "already exists") Then
     cat.Views.Delete strQryName
     Resume
  Else
     MsgBox Err.Number & ": " & Err.Description
     Resume ExitHere
  End If

End Sub

</source>
   
  

Executing a Select Query

   <source lang="vb">

Sub Execute_SelectQuery()

  Dim cmd As ADODB.rumand
  Dim myRecordset As ADODB.Recordset
  Dim strPath As String
  strPath = CurrentProject.Path & "mydb.mdb"
  Set cmd = New ADODB.rumand
  With cmd
     .ActiveConnection = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strPath
     .rumandText = "[Products by Category]"
     .rumandType = adCmdTable
  End With
  Set myRecordset = New ADODB.Recordset
  Set myRecordset = cmd.Execute
  Debug.Print myRecordset.GetString
  myRecordset.Close
  Set myRecordset = Nothing
  Set cmd = Nothing

End Sub

</source>
   
  

Get DISTINCT records

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("SELECT DISTINCT City FROM Employees ")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Get DISTINCTROW

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("SELECT DISTINCTROW CompanyName FROM Customers, Orders WHERE Customers.CustomerID = Orders.CustomerID ORDER BY CompanyName; 

«)

  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Get more than one column

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("SELECT FirstName, LastName, PhoneNo FROM Employees")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Get only one column

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("SELECT LastName FROM Employees ")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Get the top 10 percent

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("SELECT TOP 10 PERCENT * FROM Products ORDER BY UnitPrice ASC; ")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Get the top 5 percent

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("SELECT TOP 5 * FROM Products ORDER BY UnitPrice DESC ")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Loop through the ResultSet after executing select statement

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("select * from employees")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Modifying a Select Query

   <source lang="vb">

Sub Modify_Query()

  Dim cat As ADOX.Catalog
  Dim cmd As ADODB.rumand
  Dim strPath As String
  Dim newStrSQL As String
  Dim oldStrSQL As String
  Dim strQryName As String
  strPath = CurrentProject.Path & "mydb.mdb"
  newStrSQL = "SELECT Employees.* FROM Employees" & _
     " WHERE Employees.City="London"" & _
     " ORDER BY BirthDate;"
  strQryName = "London Employees"
  Set cat = New ADOX.Catalog
  cat.ActiveConnection = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strPath
  Set cmd = New ADODB.rumand
  Set cmd = cat.Views(strQryName).rumand
  oldStrSQL = cmd.rumandText
  Debug.Print oldStrSQL
  cmd.rumandText = newStrSQL
  Debug.Print newStrSQL
  Set cat.Views(strQryName).rumand = cmd
  Set cmd = Nothing
  Set cat = Nothing

End Sub

</source>
   
  

Order by two fields

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("SELECT txtCustFirstName, txtCustLastName FROM tblCustomer WHERE txtState = "NJ" ORDER BY txtCustLastName DESC, txtCustFirstName")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Order record in a decscending order

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("SELECT * FROM Employees ORDER BY Country DESC")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Order the resultset with Order by clause

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("SELECT * FROM Employees ORDER BY EmployeeID ")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Select all columns

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("SELECT * FROM Employees")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Use and to combine conditions

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("SELECT txtCustFimyRecordsetName, txtCustLastName FROM tblCustomer WHERE txtState = "NJ" AND txtCustLastName = "Miller"")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Use Between And

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("Select * FROM Products WHERE UnitPrice NOT BETWEEN 10 and 25 ")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Use between and with number type column

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("Select * FROM Products WHERE UnitPrice Between 10 and 25")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Use Date function in where clause

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("SELECT * FROM Employees WHERE ((Year([HireDate])<1993) OR (City="Redmond"))      ")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Use IN and like in where clause

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("SELECT * FROM Employees WHERE City IN ("Redmond", "London") AND ReportsTo LIKE "Buchanan, Steven" ")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Use IN in select statement

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("SELECT * FROM Employees WHERE City IN ("Redmond", "London")")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Use «Is not null»

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("Select * from Employees WHERE ReportsTo IS NOT NULL ")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Use Is NULL to check if a column is null

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("Select * from Employees WHERE ReportsTo IS NULL")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Use Not In

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("SELECT * FROM Employees WHERE City NOT IN ("Redmond", "London") ")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Use «Select all»

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("SELECT ALL * FROM Employees ORDER BY EmployeeID; ")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

use SUM in sql statement

   <source lang="vb">

Private Sub RunningSumSQL()

   Dim db As Database
   Set db = CurrentDb
   Dim qry As QueryDef
   Dim sSQL As String
   
   On Error Resume Next
   db.QueryDefs.Delete "temp"
   On Error GoTo 0
   
   sSQL = "SELECT R1.Event,(SELECT SUM(R2.Duration) FROM Running As R2 WHERE R2.Event < R1.Event) AS StartTime FROM Running As R1"
   Set qry = db.CreateQueryDef("temp", sSQL)
   DoCmd.OpenQuery qry.Name

End Sub

</source>
   
  

Use where clause and order by clause together

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("SELECT txtCustFirstName, txtCustLastName FROM tblCustomer WHERE txtState = "NJ" ORDER BY txtCustLastName, txtCustFirstName

«)

  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Use wild card character in link

   <source lang="vb">

Sub CreateRst_WithSQL()

  Dim conn As ADODB.Connection
  Dim myRecordset As ADODB.Recordset
  Dim strConn As String
  strConn = "Provider = Microsoft.Jet.OLEDB.4.0;" & _
     "Data Source=" & CurrentProject.Path & _
     "mydb.mdb"
  Set conn = New ADODB.Connection
  conn.Open strConn
  Set myRecordset = conn.Execute("SELECT txtCustFimyRecordsetName, txtCustLastName FROM tblCustomer WHERE txtCustLastName Like "M*" ")
  Do Until myRecordset.EOF
      For Each fld In myRecordset.Fields
         Debug.Print fld.Name & "=" & fld.Value
      Next fld
      myRecordset.MoveNext
  Loop
  
  myRecordset.Close
  Set myRecordset = Nothing
  conn.Close
  Set conn = Nothing

End Sub

</source>
   
  

Using Date field type in select statement

   <source lang="vb">

Sub FindProject()

   Dim strSQL As String
   Dim rst As ADODB.Recordset
   Set rst = New ADODB.Recordset
   rst.ActiveConnection = CurrentProject.Connection
   rst.CursorType = adOpenStatic
   rst.Open "Select * FROM Employees WHERE BirthDate = #12/31/2007#"
   "Attempt to find a specific project
   strSQL = "[EmployeeID] = " & 1
   rst.Find strSQL
   "Determine if the specified project was found
   If rst.EOF Then
       msgBox lngValue & " Not Found"
   Else
       msgBox lngValue & " Found"
   End If
   rst.Close
   Set rst = Nothing

End Sub

</source>
   
  

You must use a pound symbol (#) when delimiting dates for Microsoft Access, like this:

   <source lang="vb">

Sub FindProject()

   Dim strSQL As String
   Dim rst As ADODB.Recordset
   Set rst = New ADODB.Recordset
   rst.ActiveConnection = CurrentProject.Connection
   rst.CursorType = adOpenStatic
   rst.Open "Select * FROM Employees WHERE BirthDate = #12/31/2007#"
   "Attempt to find a specific project
   strSQL = "[EmployeeID] = " & 1
   rst.Find strSQL
   "Determine if the specified project was found
   If rst.EOF Then
       msgBox lngValue & " Not Found"
   Else
       msgBox lngValue & " Found"
   End If
   rst.Close
   Set rst = Nothing

End Sub

</source>

Представьте себе ситуацию, Вы получили целевую выборку из одной базы данных, но для полноты картины, как всегда, нужны дополнительные данные. Проблема может быть в том, что нужная информация хранится в другой базе данных и возможности создать на ней свою таблицу нет, подключиться используя link тоже нельзя, да и количество элементов, по которым нужно получить данные, несколько больше, чем допустимое на данном источнике. Вот и получается, что возможность написать SQL запрос и получить нужные данные есть, но написать придется не один запрос, а потом потратить время на объединение полученных данных.

Выйти из подобной ситуации поможет Excel.

Уверен, что ни для кого не секрет, что MS Excel имеет встроенный модуль VBA и надстройки, позволяющие подключаться к внешним источникам данных, то есть по сути является мощным инструментом для аналитики, а значит идеально подходит для решения подобных задач.

Для того чтобы обойти проблему, нам потребуется таблица с целевой выборкой, в которой содержатся идентификаторы, по которым можно достаточно корректно получить недостающую информацию (это может быть уникальный идентификатор, назовем его ID, или набор из данных, находящихся в разных столбцах), ПК с установленным MS Excel, и доступом к БД с недостающей информацией и, конечно, желание получить ту самую информацию.

Создаем в MS Excel книгу, на листе которой размещаем таблицу с идентификаторами, по которым будем в дальнейшем формировать запрос (если у нас есть уникальный идентификатор, для обеспечения максимальной скорости обработки таблицу лучше представить в виде одного столбца), сохраняем книгу в формате *.xlsm, после чего приступаем к созданию макроса.

Через меню «Разработчик» открываем встроенный VBA редактор и начинаем творить.

Sub job_sql() — Пусть наш макрос называется job_sql.

Пропишем переменные для подключения к БД, записи данных и запроса:

Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim sql As String

Опишем параметры подключения:

sql = «Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=True;Data Source=Storoge.company.ru Storoge.»

Объявим процедуру свойства, для присвоения значения:

Set cn = New ADODB.Connection
cn.Provider = » SQLOLEDB.1″
cn.ConnectionString = sql
cn.ConnectionTimeout = 0
cn.Open

Вот теперь можно приступать непосредственно к делу.

Организуем цикл:

For i = 2 To 1000

Как вы уже поняли конечное значение i=1000 здесь только для примера, а в реальности конечное значение соответствует количеству строк в Вашей таблице. В целях унификации можно использовать автоматический способ подсчета количества строк, например, вот такую конструкцию:

Dim LastRow As Long
LastRow = ActiveSheet.UsedRange.Row — 1 + ActiveSheet.UsedRange.Rows.Count

Тогда открытие цикла будет выглядеть так:

For i = 2 To LastRow

Как я уже говорил выше MS Excel является мощным инструментом для аналитики, и возможности Excel VBA не заканчиваются на простом переборе значений или комбинаций значений. При наличии известных Вам закономерностей можно ограничить объем выгружаемой из БД информации путем добавления в макрос простых условий, например:

If Cells(i, 2) = «Ваше условие» Then

Итак, мы определились с объемом и условиями выборки, организовали подключение к БД и готовы формировать запрос. Предположим, что нам нужно получить информацию о размере ежемесячного платежа [Ежемесячный платеж] из таблицы [payments].[refinans_credit], но только по тем случаям, когда размер ежемесячного платежа больше 0

sql = «select [Ежемесячный платеж] from [PAYMENTS].[refinans_credit] » & _
«where [Ежемесячный платеж]>0 and [Номер заявки] ='» & Cells(i, 1) & «‘ «

Если значений для формирования запроса несколько, соответственно прописываем их в запросе:

«where [Ежемесячный платеж]>0 and [Номер заявки] = ‘» & Cells(i, 1) & «‘ » & _
» and [Дата платежа]='» & Cells(i, 2) & «‘»

В целях самоконтроля я обычно записываю сформированный макросом запрос, чтобы иметь возможность проверить его корректность и работоспособность, для этого добавим вот такую строчку:

Cells(i, 3) = sql

в третьем столбце записываются запросы.

Выполняем SQL запрос:

Set rs = cn.Execute(sql)

А чтобы хоть как-то наблюдать за выполнением макроса выведем изменение i в статус-бар

Application.StatusBar = «Execute script …» & i
Application.ScreenUpdating = False

Теперь нам нужно записать полученные результаты. Для этого будем использовать оператор Do While:

j = 0
Do While Not rs.EOF
For ii = 0 To rs.Fields.Count — 1
Cells(i, 4 + j + ii) = rs.Fields(0 + ii) ‘& «;»

Указываем ячейки для вставки полученных данных (4 в примере это номер столбца с которого начинаем запись результатов)

Next ii
j = j + rs.Fields.Count
s.MoveNext
Loop
rs.Close
End If

— закрываем цикл If, если вводили дополнительные условия

Next i
cn.Close
Application.StatusBar = «Готово»
End Sub

— закрываем макрос.

В дополнение хочу отметить, что данный макрос позволяет обращаться как к БД на MS SQL так и к БД Oracle, разница будет только в параметрах подключения и собственно в синтаксисе SQL запроса.

В приведенном примере для авторизации при подключении к БД используется доменная аутентификация.

А как быть если для аутентификации необходимо ввести логин и пароль? Ничего невозможного нет. Изменим часть макроса, которая отвечает за подключение к БД следующим образом:

sql = «Provider= SQLOLEDB.1;Password=********;User ID=********;Data Source= Storoge.company.ru Storoge;APP=SFM»

Но в этом случае при использовании макроса возникает риск компрометации Ваших учетных данных. Поэтому лучше программно удалять учетные данные после выполнения макроса. Разместим поля для ввода пароля и логина на листе и изменим макрос следующим образом:

sql = «Provider= SQLOLEDB.1;Password=» & Sheets(«Лист аутентификации»).TextBox1.Value & «;User ID=» & Sheets(«Лист аутентификации «).TextBox2.Value & «;Data Source= Storoge.company.ru Storoge;APP=SFM»

Место для расположения текстовых полей не принципиально, можно расположить их на листе с таблицей в первых строках, но мне удобней размещать поля на отдельном листе. Чтобы введенные учетные данные не сохранялись вместе с результатом выполнения макроса в конце исполняемого кода дописываем:

Sheets(«Выгрузка»).TextBox1.Value = «« Sheets(»Выгрузка«).TextBox2.Value = »»

То есть просто присваиваем текстовым полям пустые значения, таким образом после выполнения макроса поля для ввода пароля и логина окажутся пустыми.

Вот такое вполне жизнеспособное решение, позволяющее сократить трудозатраты при получении и обработке данных, я использую. Надеюсь мой опыт применения SQL запросов в Excel будет полезен и вам в решении текущих задач.

  • Remove From My Forums

 locked

Excel Range in VBA SQL Query Where clause — Range like (‘xx’,’xx’,’xx’,’xx’)

  • Question

  • Dear Saviour

    I have an SQL Query I want to Run in VBA — One of the Where clauses must be selected from a Range in an Excel Worksheet — i just cant get it working…..
    Some people say I need a function, some a variable — Please help ?

    The range of values in the cells need to be like Range like (‘xx’,’xx’,’xx’,’xx’)  — then the SQL Query will bring back only records that are selected.

    I have been pulling my hair out

    Please help.

    Regards

    Raj Sharma

Answers

  • The where clause cannot be a range.  It need to be the column header (data in row 1).

    Excel requires the following properties set

    1) The excerl sheet name need to have a dollar sign at the end of the sheet name.  The excel worksheet are system tables and the Microsoft Jet Engine requires the dollar sign at the end of all system tables

    2) HDR=Yes is needed so the first row of the excel worksheet is used as the name of the column (Field) in a SQL statement

    3) Options:=adCmdText is needed when you have a Where Clause in your SQL statement.  Otherwise the default is adCmdTable and you will get an error.

    Sub GetWorksheet()
    Dim cn As ADODB.Connection
    Dim rs As ADODB.Recordset
    Set SourceSht = ThisWorkbook.Sheets("Sheet1")
    Folder = "c:Temp"
    DestFile = Folder & "book2.xls"
    'excel worksheet must have dollar sign at end of name
    DestShtName = "Sheet1" & "$"
    'open a connection, doesn't open the file
    Set cn = New ADODB.Connection
    With cn
       ConnectStr = _
          "Provider=Microsoft.Jet.OLEDB.4.0;" & _
          "Data Source=" & DestFile & ";" & _
          "Mode=Share Deny None;" & _
          "Extended Properties=""Excel 8.0;HDR=Yes;ReadOnly=False;"""
        .Open (ConnectStr)
    End With
    'open the recordset
    Set rs = New ADODB.Recordset
    With rs
       FindName = "Smith"
       MySQL = "SELECT * FROM [" & DestShtName & "] " & vbCrLf & _
               "WHERE (Name.ID=" & FindName & ")"
       
       .Open Source:=MySQL, _
          ActiveConnection:=cn, _
          CursorType:=adOpenDynamic, _
          LockType:=adLockOptimistic, _
          Options:=adCmdText
      
       If .EOF <> True Then
         
          Do While Not .EOF
             URL = ![Descriptions]
          
             .MoveNext
            
          Loop
        End If
          
    End With
    rs.Close
    Set rs = Nothing
    cn.Close
    Set cn = Nothing
    End Sub


    jdweng

    • Marked as answer by

      Friday, March 23, 2012 9:38 AM

 

Vitallic

Пользователь

Сообщений: 239
Регистрация: 23.07.2013

Добрый день. Подскажите как решить такую проблему: есть excel-файл в котором находяться нужные (но избыточные) данные.
Из него с помощью метода ADODB вытаскиваю часть данных на другой лист этой же книги. Критерий по которому происходит отбор данных находится
на исходном листе в ячейке [i1] (это для примера имя Василь). А если мне нужно использовать несколько критериев для выбора из
большой базы данных (в файле-примере это имена «Іван, Володимир» в следующих ячейках), тоесть количество ФИО по которым
надо вытянуть информацию из базы около 50,  как в таком случае построить запрос? Или нужно будет генерировать 50 запросов?

Прикрепленные файлы

  • 12.xlsm (20.03 КБ)

 

ikki

Пользователь

Сообщений: 9709
Регистрация: 22.12.2012

#2

11.02.2014 18:31:28

можно и 50
возможно, это будет даже быстрее

а можно так
перед запросом:

Код
  s = "|" & VBA.Join(Application.Transpose(ActiveSheet.[i1].CurrentRegion), "|") & "|"

сам запрос:

Код
d = "Select * From [1$] Where '|' & f5 & '|' LIKE '" & s & "'"

(обратите внимание на одинарные кавычки — синтаксисом допускается)

фрилансер Excel, VBA — контакты в профиле
«Совершенствоваться не обязательно. Выживание — дело добровольное.» Э.Деминг

 

Vitallic

Пользователь

Сообщений: 239
Регистрация: 23.07.2013

#3

11.02.2014 18:50:05

ikki, спасибо (особенно за одинарные кавычки в свое время с кавычками немало поломал голову).
что касаеться самого запроса то он после Вашых рекомендаций имеет вид:

Код
Select * From [1$] Where '|' & f5 & '|' LIKE '|Василь|Іван|Володимир|'
 

ну и по понятным причинам ничего не вытаскивает из «базы».
Я что то недопонял?
П.С. Это условно данные для критерия отбора находятся вертикально в 3 ячейках
в принципе я их и в массив могу (Array(n,n+1….)) важно понять как не делать 50 запросов
а обработать все одним (или это больше по части SQL)?

 

ikki

Пользователь

Сообщений: 9709
Регистрация: 22.12.2012

#4

11.02.2014 19:04:05

извините, ошибся — у меня старый Excel, а переписывать весь код для проверки не хотелось
запрос должен выглядеть так:

Код
d = "Select * From [1$] Where '" & s & "' LIKE '*|' & f5 & '|*'"

или так, с использованием функции VBA

Код
d = "Select * From [1$] Where InStr('" & s & "', '|' & f5 & '|')>0"

Изменено: ikki11.02.2014 19:13:48

фрилансер Excel, VBA — контакты в профиле
«Совершенствоваться не обязательно. Выживание — дело добровольное.» Э.Деминг

 

Vitallic

Пользователь

Сообщений: 239
Регистрация: 23.07.2013

Спасибо, буду разбираться
П.С. А Excel по-видимому действительно старый  ;)  

 

ikki

Пользователь

Сообщений: 9709
Регистрация: 22.12.2012

2003-й.
мне хватает   :)

пс. ещё раз скопируйте код — опять наколбасил с кавычками :(

Изменено: ikki11.02.2014 19:14:51

фрилансер Excel, VBA — контакты в профиле
«Совершенствоваться не обязательно. Выживание — дело добровольное.» Э.Деминг

 

Vitallic

Пользователь

Сообщений: 239
Регистрация: 23.07.2013

Знал что не работало еще когдпа писал предыдущее сообщение  :)
Просто неудобно было доставать
А завтра на работе обьязательно проверю последнюю версию кода
Еще раз спасибо

 

ikki

Пользователь

Сообщений: 9709
Регистрация: 22.12.2012

так и пришлось попробовать…
заодно вспомнить, что подстановочные знаки в SQL другие, чем в VBA
заодно убедиться, что у Вас в таблице дофига лишних пробелов в столбце с именами.
и что «Iван» в столбце I какой-то не такой (разбираться не стал, просто скопировал)

итого: оба способа рабочие

Изменено: ikki11.02.2014 23:33:06

фрилансер Excel, VBA — контакты в профиле
«Совершенствоваться не обязательно. Выживание — дело добровольное.» Э.Деминг

 

ikki

Пользователь

Сообщений: 9709
Регистрация: 22.12.2012

пс. само собой — без ADO (на массивах и словаре) макрос будет работать быстрее.
но интересно было всё-таки добить вариант с SQL

фрилансер Excel, VBA — контакты в профиле
«Совершенствоваться не обязательно. Выживание — дело добровольное.» Э.Деминг

 

anvg

Пользователь

Сообщений: 11878
Регистрация: 22.12.2012

Excel 2016, 365

Доброе время суток.
Если используется SQL, то всё же желательно разносить таблицы по листам. Так и сделал: таблица исходных данных на листе BaseSheet, список имён для выборки на листе QuerySheet, там же и кнопка запроса. Like лишняя конструкция — для этого лучше использовать Join.
Успехов.

Прикрепленные файлы

  • 12.xlsm (21.58 КБ)

 

Vitallic

Пользователь

Сообщений: 239
Регистрация: 23.07.2013

ikki, таки да читал где-то на форуме что быстрее на словарях-массивах, но важно было именно с помощью ADODB
поскольку в «реале» вытаскивать данные собираюсь с базы SQL, а опыта построения таких запросов нет.
anvg, очень интересно написано (неисключаю что свой пример я строил на Вами ранее написаном макросе, поскольку «нарыл» его
где-то на просторах форума и чуть-чуть покорежил).
Уважаемые планетяне, может подскажите что почитать для построения SQL-запосов из VBA?
П.С. Сейчас штудирую Грабера «Понимание SQL». Как по мне там что-то с переводом (редакция 1992) ну и как мне кажется не весь функционал
применим для использования в VBA  

 

anvg

Пользователь

Сообщений: 11878
Регистрация: 22.12.2012

Excel 2016, 365

#12

12.02.2014 11:19:29

Цитата
(неисключаю что свой пример я строил на Вами ранее написаном макросе

Судя по некоторым особенностям именования — не исключено  ;)  . При запросах к таблицам Excel используется движок Access (с некоторыми особенностями обращения к таблицам на листе [ИмяЛиста$]), так что имеет смысл поискать книжки по его диалекту SQL. Следует также учитывать то, что типы данных проверяются по первым 8 строкам (по-умолчанию) таблицы, так что желательно в них иметь заполненные данные для правильной работы.

 

Vitallic

Пользователь

Сообщений: 239
Регистрация: 23.07.2013

anvg

, еще раз спасибо.
Ушел учится  :)

 

PowerBoy

Пользователь

Сообщений: 141
Регистрация: 13.01.2014

Можете глянуть мою надстройку, пока еще бета версия. Но данные вытянет откуда хотите.   :)

http://files.mail.ru/20A7C9975D374B4FAB199D1148831349

Изменено: PowerBoy12.02.2014 11:31:52

Excel + SQL = Activetables

 

ikki

Пользователь

Сообщений: 9709
Регистрация: 22.12.2012

в офисе 97 была совершенно шикарная русская справка по ядру Microsoft Jet
и устанавливалась она по умолчанию.
сейчас глянул — в текущем 2003-м из Excel я её не вижу (видимо, настраивать надо), а из Access — прекрасно вижу.
пробежался по диагонали — вроде бы не хуже 97-го.

раздел так и называется — «Справочник Microsoft Jet SQL»
имхо, параллельное изучение с Грубером — неплохой вариант.

фрилансер Excel, VBA — контакты в профиле
«Совершенствоваться не обязательно. Выживание — дело добровольное.» Э.Деминг

 

ikki

Пользователь

Сообщений: 9709
Регистрация: 22.12.2012

зы. PowerBoy, а Вам не кажется, что Вы подобными постами (я их не первый раз вижу), нарушаете п.3.5 Правил форума?
причем из Ваших шести (на текущий момент) сообщений ровно половина — реклама Вашей надстройки.
со скринами на пол-страницы :(

Изменено: ikki12.02.2014 12:23:25

фрилансер Excel, VBA — контакты в профиле
«Совершенствоваться не обязательно. Выживание — дело добровольное.» Э.Деминг

 

PowerBoy

Пользователь

Сообщений: 141
Регистрация: 13.01.2014

#17

12.02.2014 12:25:52

Цитата
ikki пишет:
зы. PowerBoy , а Вам не кажется, что Вы подобными постами (я их не первый раз вижу), нарушаете п.3.5 Правил форума?

Не знаю —  разъясните что именно? Надстройка у меня бесплатная. К данной теме имеет прямое отношение.  

Excel + SQL = Activetables

 

ikki

Пользователь

Сообщений: 9709
Регистрация: 22.12.2012

#18

12.02.2014 12:38:04

Цитата
3.5. Рекламировать (использовать) в сообщениях, подписях, именах или аватарах любые товары и услуги, публиковать там ссылки на внешние интернет-ресурсы не имеющие отношения к обсуждаемой теме

«любые» в моём понимании — это любые.
в том числе бесплатные.
бесплатный товар всё равно является товаром.
а оговорка в Правилах про «не имеющие отношение» — относится к ссылкам (красная часть цитаты), а не к товарам и услугам (синяя часть).

и дискутировать тут не о чем.

впрочем, в Правилах есть ещё п.5.3.
им и карты в руки.

фрилансер Excel, VBA — контакты в профиле
«Совершенствоваться не обязательно. Выживание — дело добровольное.» Э.Деминг

 

The_Prist

Пользователь

Сообщений: 14182
Регистрация: 15.09.2012

Профессиональная разработка приложений для MS Office

ikki, ну это перебор. Надстройка имеет отношение к теме, я лично не вижу ничего плохого в этом. Притом тут даже не столько реклама, сколько файл. С таким же успехом можно тогда запретить и файлы с решениями выкладывать и полезными решениями.

Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы…

 

ikki

Пользователь

Сообщений: 9709
Регистрация: 22.12.2012

ок. вопросов больше нет.
трактовать правила — очевидное право модераторов.

фрилансер Excel, VBA — контакты в профиле
«Совершенствоваться не обязательно. Выживание — дело добровольное.» Э.Деминг

 

Vitallic

Пользователь

Сообщений: 239
Регистрация: 23.07.2013

а я думал тема исчерпана :)

ikki

, конечно спасибо за еще один источник информации,
помню Вы говорили что у Вас старенький Excel но не думал что такие манускрипты (MS Office 97)  ;)

PowerBoy

, к сожалению на работе (а я именно что на роботе) екзешник посмотреть не смогу
но хочу поблагодарить так как понимаю: стобы создать такого «монстра» нужно потратить неимоверную кучу усилий и времени

что же касается моей задачи то мне как раз и нужен «чистый» код поскольку я делаю какбы готовое решение не для себя (для сотрудников)
если бы это было не так я б всех не заморачивал, а использовал к примеру MS Query.

 

ikki

Пользователь

Сообщений: 9709
Регистрация: 22.12.2012

#22

12.02.2014 17:03:29

Цитата
Vitallic пишет:
MS Office 97

в 97-м году другого не было :D

фрилансер Excel, VBA — контакты в профиле
«Совершенствоваться не обязательно. Выживание — дело добровольное.» Э.Деминг

 

Tikr

Пользователь

Сообщений: 69
Регистрация: 01.01.1970

Tikr

Всем привет
Научился заливать в двумерный массив через sql запрос один dbf файл.
Но вот не задача что делать если массив надо создать из нескольких dbf файлов находящихся в разных директориях ?
При этом использую Recordset, GetRows и Connection.

 

anvg

Пользователь

Сообщений: 11878
Регистрация: 22.12.2012

Excel 2016, 365

#24

21.02.2014 02:50:43

Доброе время суток
Tikr,

Цитата
если массив надо создать из нескольких dbf файлов находящихся в разных директориях

запрос для Recordset.Open будет выглядеть приблизительно так

Код
'...
Dim sSQL As String
Dim sConn As String
'...
sConn = "Provider=VFPOLEDB.1;Data Source='c:temp';Collate=russian;Codepage=866"
'...
sSQL = "Select t1.*,t2.* From ""c:folder1table1.dbf"" As t1 Inner Join ""c:folder2table2.dbf"" As t2 On (t1.Name=t2.Name)"

Естественно сам SQL запрос по требуемому смыслу. Успехов.

 

Tikr

Пользователь

Сообщений: 69
Регистрация: 01.01.1970

Tikr

#25

21.02.2014 12:29:38

Спасибо за ответ
За это время я уже всю «нужную» базу залил в одну папку, подправил sql запрос. Если выгружать из одной таблицы, всё работает. И всё вроде бы хорошо но когда использую несколько таблиц. Возникает ошибка на строке

Код
Array = rs.GetRows

‘ Run time erroк 3021’ BOF или EOF имеет значение True, либо текущая запись удалена. Для выполнения операции требуется текущая операция
По разному пробовал и все равно каждый раз выходит эта ошибка И незнаю в чем причина толи Recordset, толи Connection, а может вообще неправильный запрос (хоть на него программа и не ругается)

 

Tikr

Пользователь

Сообщений: 69
Регистрация: 01.01.1970

Tikr

Добрый день, уважаемые коллеги!)
Касаемо последнего сообщения ошибка BOF или EOF возникла скорее всего из-за того что sql запрос ничего не посчитал и ничего не выдал Мож кому пригодится)
Помимо этого подскажите ещё. У меня есть таблица типа: Город, Продажи_фев, Продажи_мар выгрузка идет из одной базы, получается для одно колонки одно условие для другой другое
Правильно ли я понимаю таблицу надо создавать именно так и не иначе??
Select P1.Город, Р1.Сумма, Р2.Сумма
From (Select Город, Сумма, From Продажи, Where Месяц=фев) Р1,(Select Город, Сумма, From Продажи, Where Месяц=мар) Р2
WHERE P1.Город = P2.Город

А то у меня условие слишком много)))

 

PowerBoy

Пользователь

Сообщений: 141
Регистрация: 13.01.2014

#27

21.03.2014 14:05:16

Код
SELECT 
город,
SUM(iif(месяц="февраль",сумма,0)) AS сумма_фев,
SUM(iif(месяц="март",сумма,0)) AS сумма_март
FROM 
[Продажи$]
GROUP BY 
город
 

Excel + SQL = Activetables

 

Tikr

Пользователь

Сообщений: 69
Регистрация: 01.01.1970

Tikr

Добрый день!
Подтолкните в правильном направлении
Есть таблица она создается за счёт все возможных связей из разных источников Основное условие в одной таблице,  включает x параметров (например n1, n2, n3 и т.д.), для разных агентов это условие разное (например n1+n2, n3, n2+n4) Получается для каждого такого условия создаю отдельный запрос, а потом всё сливаю union all и на выходе все продажи по все агентам идут в одном поле Вопрос можно ли как-то это оптимизировать?

 

PowerBoy

Пользователь

Сообщений: 141
Регистрация: 13.01.2014

#29

23.05.2014 08:49:29

Цитата
Tikr пишет:
Подтолкните в правильном направлении

Вы запрос свой покажите, то не очень понятно.

Excel + SQL = Activetables

 

Tikr

Пользователь

Сообщений: 69
Регистрация: 01.01.1970

Tikr

#30

23.05.2014 09:15:20

Взял небольшой кусочек из основной портянки
Убрал все возможные связи, оставил только то в чем может отличаться запрос

Код
SELECT MONTH(BD.DATE) as DAT, MIN.AGENT, MIN.STROKA, Sum (([count]*([cena]/1000))) AS Summ1
FROM BD,  MIN  WHERE (MIN.PODGRUPA Is Null And MIN.NAIMEN Is Null And MIN.NOM_NAKL Is Null)
GROUP BY MONTH(BD.DATE), MIN.AGENT, MIN.STROKA
UNION all
SELECT MONTH(BD.DATE) as DAT, MIN.AGENT, MIN.STROKA, Sum (([count]*([cena]/1000))) AS Summ1
FROM BD, MIN WHERE (MIN.PODGRUPA Is Null And MIN.POLUCHA Is Null And MIN.NOM_NAKL Is Null)
GROUP BY MONTH(BD.DATE), MIN.AGENT, MIN.STROKA

UPDATE 21.10.15 Добавил «обратный» макрос — VBA в SQL и макрос для доступа к строке запроса SQL

Некоторое время назад я прошел несколько курсов по SQL. И мне было очень интересно — какую часть из мощного инструмента под названием T-SQL можно применять без использования SQL-Server (не дают мне сервачек под мои нужды, хнык-хнык).

Итак… Начнем с простого — подключение через Query Table в VBA. Можно записать через макрорекордер — для этого нужно создать подключение через Microsoft Query.

Microsoft Query

Выбираем Excel Files, указываем путь к файлу (пытаясь при этом не ругать разработчиков за интерфейс из 90х годов), фильтруем как-угодно поля. Нам сейчас это не важно — главное получить код, который дальше можно будет корректировать.

Должно получится что-то вроде этого:

Sub Макрос1()
    With ActiveSheet.ListObjects.Add(SourceType:=0, Source:=Array(Array( _
        "ODBC;DSN=Excel Files;DBQ=D:DropboxExcelтест excel_SQL-2015.xlsx;DefaultDir=D:DropboxExcel;DriverId=1046;MaxBufferSize=2048;Page" _
        ), Array("Timeout=5;")), Destination:=Range("$A$1")).QueryTable
        .CommandType = 0
        .CommandText = Array( _
        "SELECT Продажи.F2, Продажи.F3" & Chr(13) & "FROM `D:DropboxExcelтест excel_SQL-2015.xlsx`.Продажи Продажи" _
        )
        .RowNumbers = False
        .FillAdjacentFormulas = False
        .PreserveFormatting = True
        .RefreshOnFileOpen = False
        .BackgroundQuery = True
        .RefreshStyle = xlInsertDeleteCells
        .SavePassword = False
        .SaveData = True
        .AdjustColumnWidth = True
        .RefreshPeriod = 0
        .PreserveColumnInfo = True
        .ListObject.DisplayName = "Таблица_Запрос_из_Excel_Files"
        .Refresh BackgroundQuery:=False
    End With
End Sub

Строчка .CommandText = «SELECT…» — отвечает за SQL запрос. Если хотя бы немного почитать поисковую выдачу google по запросу QueryTable можно упростить код до следующего:

Sub CopyFromRecordset_To_Range()
  
  DBPath = "C:InputData.xlsx"
  sconnect = "Provider=MSDASQL.1;DSN=Excel Files;DBQ=" & DBPath & ";HDR=Yes';"
  Conn.Open sconnect
  sSQLSting = "SELECT * FROM [Sheet1$]"

  rs.Open sSQLSting, Conn
  Set QT1 = ActiveSheet.QueryTables.Add(rs, Range("A1"))
  QT1.Refresh

  rs.Close
  Conn.Close

End Sub

Теперь начинаем копаться глубже — какого уровня запросы можно строить из VBA. Самые-самые базовые, основные конструкции — все работает, все ок.

Заполнение нового столбца одинаковым значением

SELECT  'YTikhonov', * 
FROM    [Sheet1$]

Переименование столбцов

SELECT  [Advertiser] AS 'Рекламодатель', [Quantity] AS 'Количество'
FROM    [Sheet1$]

Фильтрация записей

SELECT  * 
FROM    [Sheet1$]
WHERE   [Year] = 2014

Сортировка

SELECT   * 
FROM     [Sheet1$]
ORDER BY [Advertiser] DESC

Агрегация записей

SELECT   [Advertiser], Sum([Cost]) 
FROM     [Sheet1$]
GROUP BY [Advertiser]

Работа с датой

Дату можно впрямую через конструкцию

[SomeDateField] = {ts '2015-01-01 00:00:00'}

Но я люблю отталкиваться от текущей даты. За пару текущая дата-время отвечает функция SYSDATETIME() и она может вернуть в том числе текущий день. Для этого нужна еще одна функция  — CONVERT(type,value)

SELECT CONVERT(date,SYSDATETIME())

С функцией DATEFROMPARTS строка запроса в Excel почему-то не дружит, поэтому придется использовать костыли функцию DATEADD:

DATEADD(minute, 59, DATEADD(hour, 23, DATEADD(month, MONTH(SYSDATETIME())+1, DATEADD(year, YEAR(SYSDATETIME()) - 1900, 0))))-1

Эта строчка в любой день октября 2015 вернет значение — 30.11.15 23:59

А теперь — немного best practice!

Объединение + Агрегация + Join + Подзапросы. И самое интересное — подключение к нескольким источникам:

SELECT [Year], O.Numbers, SCost, SVolume, SQuantity FROM
 (
  SELECT [Year], Month, SUM([Cost RUB]) AS SCost, SUM(Volume) AS SVolume, SUM(Quantity) AS SQuantity FROM
   (
     SELECT Advertiser, 2013 as [Year], Month, [Cost RUB], Quantity, Volume
     FROM [N:GKRadioМаркетингСлужебный2013.xlsb].[Мониторинг$]
      UNION
     SELECT Advertiser, 2014 as [Year], Month, [Cost RUB], Quantity, Volume
     FROM [N:GKRadioМаркетингСлужебный2014.xlsb].[Мониторинг$]
       UNION
     SELECT Advertiser, 2015 as [Year], Month, [Cost RUB], Quantity, Volume
     FROM [N:GKRadioМаркетингСлужебный2015.xlsb].[Мониторинг$]
   )
   WHERE [Advertiser] = 'METRO GROUP'
   GROUP BY [Year], Month
 ) as T INNER JOIN [C:testMonth.xlsb].[Test$] AS O
ON T.[Month] = O.[Month]

Одна проблема — если осуществлять такого вида запрос для соединения нескольких Excel-файлов, он будет выполняться достаточно медленно. У меня вышло порядка 2 минут. Но не стоит думать что это бесполезно — если подобные запросы выполнять при подключении к SQL-серверу, то время обработки будет 1-2 секунды (само собой, все зависит от сложности запроса, базы, и прочие прочие факторы).

Бонусы

Формировать более-менее сложный запрос SQL вручную в VBA мягко говоря неудобно.  Поэтому я написал мини-макрос, который берет информацию из буфера обмена, и возвращает туда строчки для вставки в VBE.

'работа с буфером обмена http://excelvba.ru/code/clipboard
Private Function ClipboardText() ' чтение из буфера обмена
    With GetObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
        .GetFromClipboard
        ClipboardText = .GetText
    End With
End Function
 
Private Sub SetClipboardText(ByVal txt$) ' запись в буфер обмена
    With GetObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
        .SetText txt$
        .PutInClipboard
    End With
End Sub

Public Sub SQL_String_To_VBA()
  
    Dim sInput As String, sOut As String
    Dim ArrInput, i As Integer
    
    Dim cIdent As Integer: cIdent = 1 'Count of tabs
    Dim sVar As String: sVar = "strSQL" 'Name of variable
      
    sInput = ClipboardText()
    
    ArrInput = Split(sInput, Chr(13))
    
    For i = LBound(ArrInput) To UBound(ArrInput)
        sOut = sOut & sVar & " = " & sVar & " & " & Chr(34)
        sOut = sOut & String(cIdent, Chr(9))
        sOut = sOut & Replace(ArrInput(i), Chr(10), "")
        sOut = sOut & Chr(34) & "& chr(10)" & Chr(10)
    Next i
    
    SetClipboardText (sOut)

End Sub

Public Sub VBA_String_To_SQL()
 
    Dim sInput As String, sOut As String
    Dim ArrInput, i As Integer, sTemp
 
    sInput = ClipboardText()
 
    ArrInput = Split(sInput, Chr(10))
 
    For i = LBound(ArrInput) To UBound(ArrInput)
      sTemp = Replace(ArrInput(i), "& chr(10)", "")
      If Right(sTemp, 1) = " " Then sTemp = Left(sTemp, Len(sTemp) - 1)
      If Right(sTemp, 1) = Chr(34) Then sTemp = Left(sTemp, Len(sTemp) - 1)
 
      If Len(sTemp) > 0 Then
        sTemp = Right(sTemp, Len(sTemp) - InStr(1, sTemp, Chr(34)))
        sOut = sOut & Chr(10) & sTemp
      End If
    Next i
 
    SetClipboardText (sOut)

End Sub

Сами запросы просто и удобно создавать, например, используя Notepad++. Создали многострочный запрос SQL, копируете его в буфер обмена, запускаете макрос и вуаля — в буфере обмена строчки кода, готовые для вставки в ваши макросы. При желании вы можете настроить название переменной и количество табуляций.

И еще один небольшой бонус. Если у вас есть отчет по менеджерам/руководителям, построенный на запросах, то вам наверняка потребуется получать доступ к строке запроса через VBA. Сделать это можно через замечательную команду .CommandText — работает на чтение и запись. Мне для формирования отчета на 25 человек очень пригодился.

Public Sub ReplaceCommandText()
 
Dim con As WorkbookConnection
Dim sTemp As String
 
  For Each con In ActiveWorkbook.Connections
    sTemp = con.ODBCConnection.CommandText
    con.ODBCConnection.CommandText = sTemp
    con.Refresh
  Next con
 
End Sub

PS Ссылка с ответом на вопрос — как вставить данные из Excel в SQL
https://www.simple-talk.com/sql/t-sql-programming/questions-about-using-tsql-to-import-excel-data-you-were-too-shy-to-ask/

Приятного использования!

Learn how to easily run a plain SQL query with Visual Basic for Applications on your Excel Spreadsheet.

In the last days, I received an unusual request from a friend that is working on something curious because of an assignment of the University. For this assignment, it’s necessary to find the answer or data as response of a query. Instead of a database, we are going to query plain data from an excel spreadsheet (yeah, just as it sounds). For example, for this article, we are going to use the following Sheet in Excel Plus 2016:

Excel Spreadsheet Run SQL Query

The goal of this task is to write raw SQL Queries against the available data in the spreadsheet to find the answer of the following questions:

  • Which users live in Boston.
  • Which users are boys and live in Boston.
  • Which users were born in 2012.
  • Which users were born in 2010 and were ranked in place #1.

Of course, finding such information as a regular user is quite easy and simple using filters and so, however the assignment requires to do the queries using SQL and Visual Basic for the job. In this article, I will explain you from scratch how to use Microsoft Visual Basic for Applications to develop your own macros and run some SQL queries against plain data in your excel spreadsheets.

1. Launch Microsoft Visual Basic For Applications

In order to launch the window of Visual Basic to run some code on your spreadsheets, you will need to enable the Developer tab on the excel Ribbon. You can do this easily opening the Excel options (File > Options) and searching for the Customize Ribbon tab, in this Tab you need to check the Developer checkbox to enable it in your regular interface:

Excel Ribbon Developer Tab

Click on Ok and now you should be able to find the Developer tab on your excel ribbon. In this tab, launch the Visual Basic window:

Visual Basic Ribbon Developer Excel

In this new interface you will be able to run your VB code.

2. Building connection

In the Visual Basic window, open the code window of your sheet and let’s type some code! According to your needs you may create a custom macro and assign them to the action of buttons or other kind of stuff. In this example, we are going to work with plain code and will run them independently to test them. You need to understand how to connect to the workbook data source that will be handled with the following code:

Dim connection As Object
    
'--- Connect to the current datasource of the Excel file
Set connection = CreateObject("ADODB.Connection")
With connection
    .Provider = "Microsoft.ACE.OLEDB.12.0"
    .ConnectionString = "Data Source=" & ThisWorkbook.Path & "" & ThisWorkbook.Name & ";" & _
    "Extended Properties=""Excel 12.0 Xml;HDR=NO"";"
    .Open
End With

The connection properties are described as follows:

  • Provider: we will use the Microsoft Access Database Engine 2010 (Microsoft.ACE.OLEDB.12.0)
  • ConnectionString: we will use the current excel file as the database.
  • HDR=Yes;: indicates that the first row contains the column names, not data. HDR=No; indicates the opposite.

You will use this connection to run the SQL.

3. Printing whole table data

The following example, will use the mentioned logic to connect to the current spreadsheet and will query the range A1:E6 (selecting the whole table in the example excel) and will print every row in the immediate window:

Sub MyMethod()
    '--- Declare Variables to store the connection, the result and the SQL query
    Dim connection As Object, result As Object, sql As String, recordCount As Integer
    
    '--- Connect to the current datasource of the Excel file
    Set connection = CreateObject("ADODB.Connection")
    With connection
        .Provider = "Microsoft.ACE.OLEDB.12.0"
        .ConnectionString = "Data Source=" & ThisWorkbook.Path & "" & ThisWorkbook.Name & ";" & _
        "Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
        .Open
    End With
    
    '--- Write the SQL Query. In this case, we are going to select manually the data range
    '--- To print the whole information of the table
    sql = "SELECT * FROM [Sheet1$A1:E6]"
    
    '--- Run the SQL query
    Set result = connection.Execute(sql)
    
    '--- Fetch information
    Do
        ' Print the information of every column of the result
        Debug.Print result(0); ";" & result(1) & ";" & result(2) & ";" & result(3) & ";" & result(4)
        
        result.MoveNext
        recordCount = recordCount + 1
    Loop Until result.EOF
    
    '--- Print the amount of results
    Debug.Print vbNewLine & recordCount & " results found."
End Sub

Note that we are using HDR so the query will use the first row of data as the column headers, so the result will be the following one:

Excel Spreadsheet Result Query

4. Query by columns

Now that you are able to connect to the worksheet, you may now customize the SQL to fit your needs. It is necessary to explain you the most basic thing you need to know about querying some data in your excel file. The range needs to specify the Sheet Name and the regular excel range (e.g. A1:Z1) and the whole data should be selected, not individual columns. You may filter by individual columns using regular SQL statements as WHERE, AND, OR, etc.

Depending if  you use HDR (first row contains the column names), the query syntax will change:

HDR=YES

If you have HDR enabled (in the extended properties of the connection), you may query through the column name, considering that you selected the appropriate range:

SELECT * FROM [Sheet1$A1:E6] WHERE [city] = 'Boston'

HDR=NO

If you don’t use HDR, the nomenclature of the columns will follow the F1, F2, F3, …, FN pattern:

Query Columns Excel VBA

The following query would work perfectly if you don’t have HDR enabled (note that the range changes):

SELECT * FROM [Sheet1$A2:E6] WHERE [F5] = 'Boston'

In both cases, the output will be the same in the immediate window:

Jacob;1;boy;2010;Boston
Ethan;2;boy;2010;Boston
Michael;3;boy;2010;Boston

3 results found.

5. Answering questions

The SQL that should solve the initial questions will be the following ones (with HDR disabled):

Which users live in Boston.

SELECT * FROM [Sheet1$A2:E6] WHERE [F5] = 'Boston'

Which users are boys and live in Boston.

SELECT * FROM [Sheet1$A2:E6] WHERE [F5] = 'Boston' and [F3] = 'boy'

Which users were born in 2012.

SELECT * FROM [Sheet1$A2:E6] WHERE [F4] = 2012

Which users were born in 2010 and were ranked in place #1.

SELECT * FROM [Sheet1$A2:E6] WHERE [F2] = 1 AND [F4] = 2010

Happy coding ❤️!

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 184


Репутация:

-1

±

Замечаний:
0% ±


Excel 2010

точно знаю что дату указал не верно, но по моей логике если эти переменные присвоили значения из экселя то должно работать
:'(

[vba]

Код

DECLARE @lastName nvarchar(20)=N’ЛОКАЦКАЯ’
DECLARE @firstName nvarchar(20) =N’ТАТЬЯНА’
DECLARE @secondName nvarchar(20)=N’НИКОЛАЕВНА’
DECLARE @sex nvarchar(20)=N’Ж’
DECLARE @birthDate date
set @birthDate =’18-11-1950′
——————————————————————————————
DECLARE @AfsMessage nvarchar(1000)
——————————————————————————————
DECLARE @TipPass21 nvarchar(10)=N’21’
DECLARE @seriesNumber21 nvarchar(10) =N’6502938694′
DECLARE @docdate21 date=N’15.05.2002′
DECLARE @whopass21 nvarchar(60)=N’ВЕРХНЕПЫШМИНСКИМ ГОВД СВЕРДЛОВСКОЙ ОБЛАСТИ’
DECLARE @BPID nvarchar(20)
DECLARE @BPIDID nvarchar(20)
DECLARE @BP_ID nvarchar(20)
DECLARE @OTDNUM nvarchar(20)
DECLARE @date date
DECLARE @oldFIO nvarchar(20)
DECLARE @birthPlace nvarchar(60)
DECLARE @worktel nvarchar(20)
DECLARE @mobiltel nvarchar(20)
DECLARE @contacttel nvarchar(20)
DECLARE @TipPass22 nvarchar(10)
DECLARE @seriesNumber22 nvarchar(10)
DECLARE @docdate22 varchar(20)
DECLARE @whopass22 nvarchar(60)
DECLARE @TipPass7 nvarchar(10)
DECLARE @seriesNumber7 nvarchar(10)
DECLARE @docdate7 varchar(20)
DECLARE @whopass7 nvarchar(60)
DECLARE @TipPass31 nvarchar(10)
DECLARE @seriesNumber31 nvarchar(10)
DECLARE @docdate31 varchar(20)
DECLARE @whopass31 nvarchar(60)
DECLARE @TipPass4 nvarchar(10)
DECLARE @seriesNumber4 nvarchar(10)
DECLARE @docdate4 varchar(20)
DECLARE @TipPass32 nvarchar(10)
DECLARE @seriesNumber32 nvarchar(10)
DECLARE @TipPass81 nvarchar(10)
DECLARE @seriesNumber81 nvarchar(10)
SELECT
@BPIDID=ANKETA_ID,
@BPID=ANKETA_ID,
@BP_ID=BP_ID,
@OTDNUM=CASE a.ANKETA_OTDNUM WHEN 90 THEN ‘2’ ELSE ‘1’ END,
@lastName=ANKETA_FAM,
@firstName=ANKETA_IM,
@secondName=ANKETA_OT,
@oldFIO=UBRR_ANKETA_OLDFIO,
@birthDate=ANKETA_BIRTH_DATE,
@birthPlace=ANKETA_BIRTHPLACE,
@sex=CASE ANKETA_SEX WHEN N’Ж’ THEN 0 ELSE 1 END,
@date=CONVERT(nvarchar(10),GETDATE(),104),
——————————————————————————————
@TipPass4=’4′,
@seriesNumber4=ISNULL(SUBSTRING(ANKETA_SERIESOFFICER,1,2)+SUBSTRING(ANKETA_SERIESOFFICER,4,2)+ANKETA_NUMBEROFFICER,»),
@docdate4=ANKETA_DATEOFFICER,
——————————————————————————————
@TipPass7=’7′,
@seriesNumber7=ISNULL(SUBSTRING(ANKETA_SERIESCARD,1,2)+SUBSTRING(ANKETA_SERIESCARD,4,2)+ANKETA_NUMBERCARD,»),
@docdate7=ANKETA_DATECARD,
@whopass7=ANKETA_WHOCARD,
@TipPass31=’31’,
@seriesNumber31=ISNULL(SUBSTRING(ANKETA_SERIESDRIVER,1,2)+SUBSTRING(ANKETA_SERIESDRIVER,4,2)+ANKETA_NUMBERDRIVER,»),
@docdate31=ANKETA_DATEDRIVER,
@whopass31=ANKETA_WHODRIVER,
@TipPass22=’22’,
@seriesNumber22=ANKETA_NUMBERZAGR,
@docdate22=ANKETA_DATEZAGR,
@whopass22=ANKETA_WHOZAGR,
——————————————————————————————
@TipPass21=’21’,
@seriesNumber21=ISNULL(SUBSTRING(ANKETA_SERIESPASSPORT,1,2)+SUBSTRING(ANKETA_SERIESPASSPORT,4,2)+ANKETA_NUMBERPASSPORT,»),
@docdate21=ANKETA_DATEPASSPORT,
@whopass21=ANKETA_WHOPASSPORT,
——————————————————————————————
@TipPass32=’32’,
@seriesNumber32=ANKETA_NUMBERSTATEINC,
——————————————————————————————
@TipPass81=’81’,
@seriesNumber81=ANKETA_INN,

FROM port.Ankets a

DECLARE  @URL  SysName
,@Body xml

— Создание запроса
;WITH XMLNAMESPACES (DEFAULT ‘http://mbtc.ru/afs/’)

SELECT  @URL    = ‘http://sas-afs.lan.ubrr.ru:8080/afs/ws/ubrrService’
    ,@Body  = (
SELECT  
‘LoyaltyWS’ as [auth/login],
‘LoyaltyWS1!’ as [auth/password],
‘match’ as [action],
‘STOP_LIST_1’ as [ruleSetId],
@BPID as [Application/id],
‘1’ as [Application/version],
@date as [Application/date],
@OTDNUM as [Application/app/bank],
@BPIDID as [Application/app/formId],
@BP_ID as [Application/app/applicant/id],
@lastName as [Application/app/applicant/person/lastName],
@firstName as [Application/app/applicant/person/firstName],
@secondName as [Application/app/applicant/person/secondName],
@oldFIO as [Application/app/applicant/person/prevFullName],
@birthDate as [Application/app/applicant/person/birthDate],
@birthPlace as [Application/app/applicant/person/birthPlace],
@sex as [Application/app/applicant/person/sex],
—————————————-DOC—————————————————————
(SELECT f.*
FROM
(
values
(@TipPass21,@seriesNumber21,@docdate21,@whopass21),
(@TipPass22,@seriesNumber22,@docdate22,@whopass22),
(@TipPass7,@seriesNumber7,@docdate7,@whopass7),
(@TipPass31,@seriesNumber31,@docdate31,@whopass31),
(@TipPass4,@seriesNumber4,@docdate4,»),
(@TipPass32,@seriesNumber32,»,»),
(@TipPass81,@seriesNumber81,»,»)
)
f([type], seriesNumber, date, issued)for xml path(‘doc’), type)
as [Application/app/applicant],
—————————————ADDRES————————————————————
(SELECT a.*
FROM
(
values
(1, @regionReg, @indexReg,@regarea, @cityReg,@regplace, @streetReg, @houseReg, @corpReg, @flatReg),
(2, @regionLife, @indexLife,@lifearea, @cityLife,@lifeplace, @streetLife, @houseLife, @corpLife, @flatLife)
)
a([type], region, postalCode,area, city,place, street, house, corp, flat)for xml path(‘address’), type)
as [Application/app/applicant/addresses],
@residenceChange as [Application/app/applicant/addresses/residenceChange],
@buildingType as [Application/app/applicant/addresses/buildingType],
@owner as [Application/app/applicant/addresses/owner],
—————————————-PHONE————————————————————
(SELECT s.*
FROM
(
values
(1,@housetel ),
(2,@worktel ),
(3,@mobiltel)
)
s([type],number)for xml path(‘phone’), type)
as [Application/app/applicant]
———————————————————————————————————
FOR    XML Path(‘afsRequest’),Type)
EXEC    dbo.sp_SOAPMethodCall
   @URL
  ,NULL
  ,@Body  OUT
;
SET @AfsMessage=ISNULL(@Body.value(‘declare namespace p1=»http://mbtc.ru/afs»;
(/p1:afsResponse/p1:matchResult/p1:match/p1:description)[1]’,’nvarchar(1000)’),N’По клиенту ничего не найдено.’);
with xmlnamespaces(default ‘http://mbtc.ru/afs’)
select
@AfsMessage=ISNULL(stuff(t.n.query(‘for $d in (match/description) return concat(«; «, $d/text()[1])’).value(‘.’, ‘nvarchar(max)’), 1, 2, »),N’По клиенту ничего не найдено.’)
from
@Body.nodes(‘/afsResponse/matchResult’) t(n);
SELECT @AfsMessage

[/vba]


Каждый сам выбирает правила игры

Понравилась статья? Поделить с друзьями:
  • Where something comes from word
  • Where is word to your mother from
  • Where is what type of word
  • Where is what kind of word
  • Where is vba in excel