Since I cannot seem to use the ? in the more complex SQL statements we are executing we read somewhere that you can set a previous step to setup the SQL for you. This is an ActiveX step which sets the steps SQL statement and substitutes in global variables.
So the SQL step has SELECT 0 in it and the step before it is essentially a VB Script as below
' 205 (Change SourceSQLStatement)
Option Explicit
Function Main()
Dim oPkg, oDataPump, sSQLStatement
' Build new SQL Statement
sSQLStatement = "IF (SELECT 1 FROM TABLE fm WHERE NOT EXISTS ("&_
"SELECT HighestVersionReceived "&_
"FROM FILE_CURRENT fc "&_
"WHERE fc.COL = fm.COL "&_
"AND fc.HighestVersionReceived < fm.FileVersion) "&_
"AND [FileName] = '" & DTSGlobalVariables("GLBFileName").Value & "') = 1 "&_
"SELECT 1 AS VALID "&_
"ELSE "&_
"SELECT 0 AS VALID"
' Get reference to the DataPump Task
Set oPkg = DTSGlobalVariables.Parent
Set oDataPump = oPkg.Tasks("DTSStep_DTSExecuteSQLTask_34").CustomTask
' Assign SQL Statement to Source of DataPump
oDataPump.SourceSQLStatement = sSQLStatement
' Clean Up
Set oDataPump = Nothing
Set oPkg = Nothing
Main = DTSTaskExecResult_Success
End Function
However it states it cannot find task with this name, it does exist. If we change it to Steps intead of Tasks it's found but the Step doesn't have a SourceSQLStatement property.
So i'm out of my depth. Any ideas?
Probably change the type of step that runs the SQL?
Have you tried changing the complex TSQL statement to a stored procedure?
You could then have an input parameter in the stored procedure for FileName. This stored procedure could be used as the source of your data pump task, with the parameter assigned the value of the DTS global variable at run-time by the "?" syntax you mention.
Related
Working in Access 2010 against an Access DB, I created a query in the QBE. As part of an overly complex quarterly reporting process, I now need to be able to execute that query with different parameters via VBA code. The SQL for the query is now embedded in my VBA module, and is modified on the fly, then executed. When run in the QBE, this particular instance of the query returns 400+ rows of data, but none are returned when executed in VBA via this code:
Dim Data As New ADODB.Recordset
Dim SQLString As String
SQLString = "SELECT PatientStatSchedDataDump.PtCompID, AppType.ProviderW, " & _
"PatientStatSchedDataDump.Date, PatientStatSchedDataDump.Status " & _
"FROM (AppType INNER JOIN PatientStatSchedDataDump ON AppType.AType = " & _
"PatientStatSchedDataDump.Type) LEFT JOIN GroupType ON AppType.Group = " & _
"GroupType.Group " & _
"WHERE (((PatientStatSchedDataDump.PtCompID) Like 'ClientName*' ) " & _
"AND ((PatientStatSchedDataDump.Date) BETWEEN #1/1/2014# AND #3/31/2014#) " & _
"AND ((GroupType.[Sort Order]) IN ('A', 'B', 'C', 'D', 'E')))"
Data.Open Source:=SQLString, ActiveConnection:=CurrentProject.Connection
If Not Data.EOF And Not Data.BOF Then
'the IF is never true - EOF & BOF are always True
NewSheet.Cells(InstCountRow + InstCount + 2, 1).CopyFromRecordset Data
End If
Data.Close
Set Data = Nothing
Again, if I create a new query in Access, paste the SQL code into the SQL window and run it, I get 400+ rows of results with this exact query
A query run from ADO requires ANSI wild cards: % instead of *; and _ instead of ?.
So change this ...
"WHERE (((PatientStatSchedDataDump.PtCompID) Like 'ClientName*' ) "
to this ...
"WHERE (((PatientStatSchedDataDump.PtCompID) Like 'ClientName%' ) "
If you want one query which works the same when run from ADO as it does when run in the QBE, you can use ALike instead of Like. With ALike, the db engine always expects ANSI wildcards.
"WHERE (((PatientStatSchedDataDump.PtCompID) ALike 'ClientName%' ) "
I am connecting to a SQL Server and am trying to limit the results by adding parameters. The first parameter I added, #sdate, worked just fine. But, now I am trying to add a second parameter which is not working. I want the field, LP_EOC_DATA.PL, to only be returned if the length of the string is greater than 6 characters long. The code below executed, and like I say, the dates returned were correct, but it also returned values from LP_EOC_DATA.PL that had string lengths less than 6. Please let me know if you know how to get this to work. Thanks in advance.
Sub doSQL()
Dim myConn As SqlConnection
Dim myCmd As SqlCommand
Dim myReader As SqlDataReader
Dim sqlString As String = "SELECT LP_EOC_DATA.PL as PLs, LP_EOC_DATA.cDate as ReadDate, LP_EOC_LOV.LOCATION as Location " &
"FROM LP_EOC_DATA INNER JOIN LP_EOC_LOV ON LP_EOC_DATA.PIC = LP_EOC_LOV.PIC " &
"WHERE LP_EOC_DATA.cDate > (#sdate) AND LEN(LP_EOC_DATA.PL) > #slen1 " &
"UNION SELECT dbo.VT_DATA.PL as PLs, dbo.VT_DATA.cDate as ReadDate, dbo.VT_LOV.LOCATION as Location " &
"FROM dbo.VT_DATA INNER JOIN dbo.VT_LOV ON dbo.VT_DATA.PIC = dbo.VT_LOV.PIC " &
"WHERE dbo.VT_DATA.cDate > (#sdate) AND LEN(dbo.VT_DATA.PL) > #slen1 " &
"ORDER BY ReadDate;"
myConn = New SqlConnection("SERVER=ServerName;UID=uName;" &
"PWD=Password;")
myCmd = myConn.CreateCommand
myCmd.CommandText = sqlString
myCmd.Parameters.AddWithValue("#sdate", DateTimePicker1.Value)
myCmd.Parameters.AddWithValue("#slen1", 6)
'myCmd.Parameters.AddWithValue("#rx1", "'%[^0-9a-z]%'")
'myCmd.Parameters.AddWithValue("#rx2", " dbo.VT_DATA.PL NOT LIKE '%[^0-9a-z]%'")
myConn.Open()
myReader = myCmd.ExecuteReader()
Table.Load(myReader)
DataGridView1.Visible = True
DataGridView1.DataSource = Table
lblTotal.Text = Table.Rows.Count
End Sub
Also, as you can see, I am looking to add another parameter that only returns alphanumeric results from the same LP_EOC_DATA.PL field. I haven't got quite that far yet, but if you see something I'm doing wrong there too, I'd appreciate the input.
It helps if you format your SQL a little more. There's some structure, but it still comes off as a big wall of text. It's even harder for us to debug than it is for you, since we don't know your schema at all. There are also a number of other little things you should do different before we even address the question (Using block so connection is closed in case of exception, avoid AddWithValue() for index safety, isolate SQL from user interface, etc):
Function doSQL(StartDate As DateTime) As DataTable
Dim result As New DataTable
Dim sqlString As String = _
"SELECT LP_EOC_DATA.PL as PLs, LP_EOC_DATA.cDate as LPRReadDate, LP_EOC_LOV.LOCATION as Location " &
"FROM LP_EOC_DATA " &
"INNER JOIN LP_EOC_LOV ON LP_EOC_DATA.PIC = LP_EOC_LOV.PIC " &
"WHERE LP_EOC_DATA.cDate > #sdate AND LEN(COALESCE(LP_EOC_DATA.PL,'')) > #slen1 " &
"UNION " &
"SELECT dbo.VT_DATA.PL as PLs, dbo.VT_DATA.cDate as ReadDate, dbo.VT_LOV.LOCATION as LPRLocation " &
"FROM dbo.VT_DATA " &
"INNER JOIN dbo.VT_LOV ON dbo.VT_DATA.PIC = dbo.VT_LOV.PIC " &
"WHERE dbo.VT_DATA.cDate > #sdate AND LEN(COALESCE(dbo.VT_DATA.PL,'')) > #slen1 " &
"ORDER BY ReadDate;"
Using myConn As New SqlConnection("SERVER=ServerName;UID=uName;" &
"PWD=Password;"), _
myCmd As New SqlCommand(sqlString, myConn)
myCmd.Parameters.Add("#sdate", SqlDbType.DateTime).Value = StarDate
myCmd.Parameters.Add("#slen1", SqlDbType.Int).Value = 6
myConn.Open()
result.Load(myCmd.ExecuteReader())
End Using
Return result
End Function
And then call it like this:
Dim tbl As DataTable = doSql(DateTimePicker1.Value)
DataGridView1.Visible = True
DataGridView1.DataSource = tbl
lblTotal.Text = tbl.Rows.Count
As for the question, there are a few possibilities: NULL values can give unexpected results in this kind of situation (the code I posted already accounts for that). You may also have trouble with certain unicode whitespace padding your character count. Another possibility is char or nchar fields instead of varchar or nvarchar, though I don't think that's the issue here.
This is not an answer to the question per se but a reply to the request for an XML literal example. As that requires a few lines of code, I'd rather not put it in a comment.
Dim sql = <sql>
SELECT *
FROM MyTable
WHERE MyColumn = #MyColumn
</sql>
Dim command As New SqlCommand(sql.Value, connection)
Note that the element name can be anything you want but I usually use 'sql' when it's for SQL code.
Good Afternoon,
I have an access query that contains a list of all my customers lets call that CUS
I have another query that has a list of ORDERS
I would like to write some VBS that cycles through the customer list and exports a csv file containing all orders that belong to that customer.
The vba would then move on to the next customer on the list and perform the same action.
Any help would be great.
Snippet of code below
almost there cant get the WHERE condition working it keeps displaying a popup for me to populate however the same string is feeding the msgbox fine here is a snippet below tht is within the loop
strcustcode = rs!OCUSTCODE
ordercount = rs!orders
TIMEFILE = Format$(Time, "HHMM")
MsgBox ([strcustcode] & " has " & [ordercount] & " orders")
StrSQL = "Select * From [24-ND_Cus] where [24-ND_Cus].[OCUSTCODE] = strcustcode "
Set qd = db.CreateQueryDef("tmpExport", StrSQL)
DoCmd.TransferText acExportDelim, , "tmpExport", "c:file.csv" db.QueryDefs.Delete "tmpExport" –
Don't use [ ] around VBA variables. Don't use parens for the MsgBox when you just want to give user a message. The parens make it a function that requires a response by user to set a variable.
MsgBox strcustcode & " has " & ordercount & " orders"
Concatenate the variable into the SQL statement. If OCUSTCODE is a text type field, use apostrophe delimiters for the parameter.
StrSQL = "Select * From [24-ND_Cus] Where [OCUSTCODE] = '" & strcustcode & "'"
I don't advise code that routinely modifies design and changing a query SQL statement is changing design. If the only change is filter criteria and a dynamic parameterized query won't work, I suggest a 'temp' table - table is permanent, data is temporary. Delete and write records to the table and export the table.
I am stymied by an SQL mediated import of a CSV file using VBA code. I am using a Third EXCEL macro/spreadsheet, to analyze a LEFT JOIN of 2 files, one as an XLXS and the other as a CSV.
I suspect that part of the problem may be how the SQL command is used, for a FROM reference to an excel file. I am using Excel VBA, 2010, The 14 Database Access Engine.
I want to end with an SQL statement that pulls from an external comma delimited CSV file
I anticipate heading the macro with this pseudo code, in a stand-alone macro enabled excel file:
dbEngine = CreateObject(DAO.engine ... )
set DB = dbEngine.OpenDatabase(theNormalExternalExcellFile,....)
For the SQL statement, in pseudo-code, I want this:
SELECT fields
FROM [Table$] ' a normal external excel file
LEFT JOIN [an external CSV, comma delimited file]
ON...
GROUP...
I can successfully import an XLXS, or the CSV, independently, in a simple SQL statement, yet when I place the outside file references within an SQL's FROM clause, I get one of two errors, depending on how I play with the code: an Invalid File Path, or an error in the FROM Clause. The path is -not- invalid.
The error is shown, below, where it occurs, at the recordset instruction.
I also provide alternative SQL strings, which I had played with to test where in the code the error is generated.
'the Seating Chart
strPathSource = ThisWorkbook.Worksheets("Logic").Range("rngPathSource")
'strFileNameSource = ThisWorkbook.Worksheets("Logic").Range("rngFileNameSource")
'strFileNameSourceWOExt = Left(strFileNameSource, Len(strFileNameSource) - 4)
'the attendance
strPathAttendance = ThisWorkbook.Worksheets("Logic").Range("rngPathAttendance")
strFileNameAttendance = ThisWorkbook.Worksheets("Logic").Range("rngFileNameAttendance")
strFolderAttendance = ThisWorkbook.Worksheets("Logic").Range("rngFolderAttendance")
strFileNameAttendanceWOExt = Left(strFileNameAttendance, Len(strFileNameAttendance) - 4)
Set dbE = CreateObject("Dao.DBEngine.120")
Set db = dbe.OpenDatabase(strPathSource, True, False, "Excel 12.0;HDR=Yes")
''Set db = DAO.OpenDatabase(strFolderAttendance, True, False, "text;HDR=Yes;FMT=Delimited(,)")
'[Master$] is a tab on the spreadsheet at strPathSource
'[Attendance#csv]
' This reference to the table at strPathAttendance which otherwise works: [Attendance#csv]
' when not inside the FROM clause
strSQL = _
"SELECT tM.Job, Count(tA.Name) AS CountOfName" _
& " FROM [Master$] tM" _
& " LEFT JOIN" _
& " (SELECT * FROM [text;HDR=Yes;FMT=Delimited(,);Database='" _
& strPathAttendance & "'].[" & strFileNameAttendanceWOExt & "#csv]) tA" _
& " ON (tM.GivenName = tA.GivenName) AND (tM.SurName = tA.SurName)" _
& " GROUP BY tM.Job" _
& " ORDER BY tM.Job, Count(tA.Name)"
'Debug.Print strSQL
' This is the reported value for the string, strSQL, particularly the FROM clause:
' SELECT tM.Job, Count(tA.Name) AS CountOfName FROM [Master$] tM LEFT JOIN
' (SELECT * FROM
' [text;HDR=Yes;FMT=Delimited(,);Database=T:\Solutions Team Shared Folder\Seats -
' Attendance\Attendance.csv].[Attendance#csv]) tA
' ON (tM.GivenName = tA.GivenName) AND (tM.SurName = tA.SurName)
' GROUP BY tM.Job ORDER BY tM.Job, Count(tA.Name)
'' putting a single or double quote, around the database path, does not change the error
Set rstR = db.OpenRecordset(strSQL)
'Error:
' 'T:\...\...\Attendance.csv' is not a valid path. Make sure that
' the path name is spelled correctly and that you are connected to the server
' on which the file resides.
' ALT SQL strings, to test what's going on.
'strSQL = _
' "Select * FROM [Attendance#csv]"
'strSQL = _
' "Select * FROM (Select * FROM [Excel 12.0;HDR=Yes;Database=" & strPathSource & "].[Master$])"
'strSQL = _
' "SELECT * FROM [text;HDR=Yes;FMT=Delimited(,);Database=" _
' & strPathAttendance & "].[" & strFileNameAttendanceWOExt & "#csv]"
'strSQL = _
' "Select * FROM [Excel 12.0;HDR=Yes;Database=" & strPathSource & "].[Master$]"
When connected to text files with Jet/ACE SQL, the database parameter needs to reference the directory path not any specific text file. The period qualifier will then specify the individual file.
Therefore, simply remove the file name and extension from strPathAttendance (without quotes). So query should look like the below:
SELECT tM.Job, Count(tA.Name) AS CountOfName
FROM [Master$] tM
LEFT JOIN
(SELECT * FROM
[text;HDR=Yes;FMT=Delimited(,);Database=T:\Solutions Team Shared Folder\Seats -
Attendance].[Attendance#csv]) tA
ON (tM.GivenName = tA.GivenName) AND (tM.SurName = tA.SurName)
GROUP BY tM.Job
ORDER BY tM.Job, Count(tA.Name)
I have the following expression, which goes to a SQL table (SQL Server 2008 R2) and grabs the file path to open (usually a PDF or photo) which is formatted to work as a hyperlink in our Access front-ends.
Here's what I'm doing in my VBS file...
Dim Input
Input = InputBox("Enter your WO#", "PDF Search", "ie. 40900500")
set conn2 = createobject("ADODB.Connection")
conn2.open "Driver={SQL Server}; Server=server; UID=user; PWD=password; Database=db;"
dim sql2
msgbox("Testing fixture connection...")
dim rs2
set rs2 = createobject("ADODB.Recordset")
sql2 = "select Photo from Fixtures where Application = '" & input & "'"
rs2.open sql2, conn2
msgbox("It worked! Your photo is here: " & rs2.fields(0).value)
...which eventually returns this...
...and all I need is the file path prior to the first number sign (this message box was just to test the connection and show what data I'm working with).
How would I left truncate the field value I'm returning from SQL up to the first number sign so I can open the file via running a powershell object within my .vbs file?
Any assistance is always welcome! :)
1) You could use following expression to extract file path before first #:
sql2 = "select LEFT(Photo, NULLIF(CHARINDEX('#', Photo), 0) - 1) from Fixtures where ..."
If some rows doesn't contain # then you could use:
sql2 = "select LEFT(Photo, ISNULL(NULLIF(CHARINDEX('#', Photo), 0) - 1, 260)) from Fixtures where ..."
Test:
DECLARE #Photo VARCHAR(260)
SET #Photo = 'J:\DRAWINGS\Folder1\File1.jpg#aaa#'
SELECT LEFT(#Photo, NULLIF(CHARINDEX('#', #Photo), 0) - 1) AS T1
-- J:\DRAWINGS\Folder1\File1.jpg
SET #Photo = 'J:\DRAWINGS\Folder1\File1.jpg'
SELECT LEFT(#Photo, ISNULL(NULLIF(CHARINDEX('#', #Photo), 0) - 1, 260)) AS T2
-- J:\DRAWINGS\Folder1\File1.jpg
2) You should avoid string concatenation in above line
sql2 = "select Photo from Fixtures where Application = '" & input & "'"
and you should use parameterized queries => see SQL Injections.