While moving back-end from Access .mdb file to SQL Server, the following problem was discovered.
If you join two tables A and B and there are several rows in A for one row in B Access sequentially updates target row in B with each rows of A. SQL Server acts differently (and as written in manual): target row in B is updated by one random row of A.
For MS Access
CurrentDb.Execute "CREATE TABLE A (id int, valA real);"
CurrentDb.Execute "CREATE TABLE B (id int, valB real);"
CurrentDb.Execute "insert into A(id, valA) VALUES (1, 1);"
CurrentDb.Execute "insert into A(id, valA) VALUES (1, 2);"
CurrentDb.Execute "insert into A(id, valA) VALUES (1, 3);"
CurrentDb.Execute "insert into A(id, valA) VALUES (2, 1);"
CurrentDb.Execute "insert into A(id, valA) VALUES (2, 2);"
CurrentDb.Execute "insert into A(id, valA) VALUES (3, 0);"
CurrentDb.Execute "insert into B(id, valB) VALUES (1, 0);"
CurrentDb.Execute "insert into B(id, valB) VALUES (2, 0);"
CurrentDb.Execute "insert into B(id, valB) VALUES (3, 0);"
CurrentDb.Execute "UPDATE A INNER JOIN B ON A.id = B.id SET B.valB = B.valB + A.valA;"
docmd.OpenTable "B"
Access result:
id valB
1 6
2 3
3 0
For SQL Server
CREATE TABLE A (id int, valA real);
insert into A(id, valA) VALUES (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (3, 0);
CREATE TABLE B (id int, valB real);
insert into B(id, valB) VALUES (1, 0), (2, 0), (3, 0);
UPDATE B SET B.valB = B.valB + A.valA
FROM A INNER JOIN B ON A.id = B.id ;
SELECT * FROM B;
SQL Server result
id valB
1 1
2 1
3 0
I need to get MS Access results in SQL Server. For this small and easy query it is possible to correct command in this way
UPDATE B
SET B.valB = B.valB + AA.valA
FROM (SELECT SUM(valA) as valA, id
FROM A GROUP BY id) AS AA
INNER JOIN B ON AA.id = B.id ;
But I have 150 update queries with 3 to 5 joined tables and it's hard to write parser which could fix them.
There are even such queries to write count of lines in A to B.valB, and it works well in Access, but sets B.valB = 1 at SQL server
UPDATE A INNER JOIN B ON A.id = B.id SET B.valB = B.valB + 1;
Typical four tables query :
UPDATE
vrtReserved
SET
vrtReserved.qtyOutput = Round([vrtReserved].[qtyOutput] + [ComplexRes].[Qty], 3)
FROM
Complex
INNER JOIN ((vrtReserved
INNER JOIN ComplexRes ON (vrtReserved.Code = ComplexRes.Code) AND (vrtReserved.UE = ComplexRes.UE))
INNER JOIN ComplexDetail ON (vrtReserved.flagDAV = ComplexDetail.flagDAV) AND (ComplexRes.CodeComplDetail = ComplexDetail.CodeComplDetail)) ON (vrtReserved.CodeBox = Complex.CodeBox) AND (Complex.CodeCompl = ComplexDetail.CodeCompl) AND (Complex.CodeCompl = ComplexRes.CodeCompl);
Must be rewritten to
WITH CTE AS
(
SELECT vrtReserved.CodeBox, vrtReserved.Code, vrtReserved.UE, vrtReserved.flagDAV, Sum(ComplexRes.Qty) AS [Sum-Qty]
FROM Complex INNER JOIN ((vrtReserved INNER JOIN ComplexRes ON (vrtReserved.UE = ComplexRes.UE) AND (vrtReserved.Code = ComplexRes.Code)) INNER JOIN ComplexDetail ON (ComplexRes.CodeComplDetail = ComplexDetail.CodeComplDetail) AND (vrtReserved.flagDAV = ComplexDetail.flagDAV)) ON (Complex.CodeCompl = ComplexDetail.CodeCompl) AND (Complex.CodeCompl = ComplexRes.CodeCompl) AND (Complex.CodeBox = vrtReserved.CodeBox)
GROUP BY vrtReserved.CodeBox, vrtReserved.Code, vrtReserved.UE, vrtReserved.flagDAV, vrtReserved.qtyOutput
)
UPDATE
vrtReserved
SET
vrtReserved.qtyOutput = Round([vrtReserved].[qtyOutput] + [Sum-Qty], 3)
FROM
vrtReserved
INNER JOIN
CTE
ON (vrtReserved.Code = CTE.Code) AND (vrtReserved.UE = CTE.UE) AND (vrtReserved.flagDAV = CTE.flagDAV) AND (vrtReserved.CodeBox = CTE.CodeBox);
Is there any other way except manual correction of query's text to reproduce MS Access results at SQL Server?
Interesting observation! Likely, MS Access updates multiple times for each join match rendering a cumulative sum update whereas SQL Server updates only once on the first instance of each join match.
Consider using a window function to stay at unit level and avoid the aggregate subquery:
UPDATE B
SET B.valB = B.valB + t.cum_sum
FROM B
INNER JOIN
(SELECT A.ID, SUM(A.valA) OVER(PARTITION BY A.id) AS cum_sum
FROM A
INNER JOIN B ON A.ID = B.ID) t
ON B.ID = t.ID;
Or with a CTE:
WITH CTE AS
(
SELECT A.ID, SUM(A.valA) OVER(PARTITION BY A.id) AS cum_sum
FROM A
INNER JOIN B ON A.ID = B.ID
)
UPDATE B
SET B.valB = B.valB + CTE.cum_sum
FROM B
INNER JOIN CTE
ON B.ID = CTE.ID;
Rextester Demo
I tried changing the order TSQL seems to use the first value. This is non-deterministic as a table is not supposed to have a natural order.
declare #a table (id int, val int)
insert into #a(id, val) VALUES (1, 2), (1, 1), (1, 3), (2, 1), (2, 2), (3, 0);
declare #b table (id int, val int);
insert into #b (id, val) VALUES (1, 0), (2, 0), (3, 0);
UPDATE b SET b.val = b.val + a.val
FROM #a a
INNER JOIN #b b
ON a.id = b.id
SELECT * FROM #b;
Not a lot of help you you could create views for sum and count to not repeat as much code.
The only solution I can found is:
create table A (id int, valA real)
insert into A(id, valA) VALUES (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (3, 0)
create table B (id int, valB real)
insert into B(id, valB) VALUES (1, 0), (2, 0), (3, 0)
UPDATE B SET B.valB += (SELECT SUM(valA) FROM A WHERE A.id=B.id)
select * from B
as Microsoft says here and there,
a single UPDATE statement never updates the same row two times.
With some limitations and assumptions this code work well with queries in my database
Public Function UpSizeUPDATEwithJOIN(tsqlText As String, Optional fMultiLineOutput As Boolean) As String
' transform TSQL UPDATE with JOINS and repeatable self assigments to UPDATE with CTE, GROUP BY and SUM
' test commands
'?UpSizeUPDATEwithJOIN("UPDATE B SET B.valB = B.valB + A.valA FROM A INNER JOIN B ON A.id = B.id ;",true)
'?UpSizeUPDATEwithJOIN("UPDATE vrtРезерв SET vrtРезерв.КвоВыдано = Round([vrtРезерв].[КвоВыдано]+[КомплектРез].[Кво],3.0), vrtРезерв.ДолгВыдать = vrtРезерв.ДолгВыдать - [КомплектДет].[Списано] FROM Комплект INNER JOIN ((vrtРезерв INNER JOIN КомплектРез ON (vrtРезерв.Код = КомплектРез.Код) AND (vrtРезерв.ВЭ = КомплектРез.ВЭ)) INNER JOIN КомплектДет ON (vrtРезерв.przDav = КомплектДет.przDav) AND (КомплектРез.КодКомплДет = КомплектДет.КодКомплДет)) ON (vrtРезерв.КодКор = Комплект.КодКор) AND (Комплект.КодКомпл = КомплектДет.КодКомпл) AND (Комплект.КодКомпл = КомплектРез.КодКомпл);",true)
Dim tmpSQL As String
Dim nameTargetTable As String
Dim enameTargetTable As String
Dim cLenTableEName As Long
Dim cLenTableName As Long
Dim strNL As String
If fMultiLineOutput Then
strNL = vbNewLine
End If
nameTargetTable = unWrapWith(Trim(GetInner(tsqlText, "UPDATE ", " SET")), "[", "]") ' table
enameTargetTable = wrapWith(nameTargetTable, "[", "]") ' [table]
cLenTableEName = Len(enameTargetTable)
cLenTableName = Len(nameTargetTable)
Dim tsqlFROMpart As String
Dim dictGROUPBYFields As Dictionary
tsqlFROMpart = GetInnerEx(tsqlText, "FROM ", "WHERE ", ";", """", "<EOL>")
Set dictGROUPBYFields = New Dictionary
dictGROUPBYFields.CompareMode = TextCompare ' means Table = TaBlE
Dim posAt As Long
Dim posStart As Long
Dim posEnd As Long
Dim strConditions As String
Dim arrConditions() As String
Dim strCurrCond As String
Dim strParts() As String
Dim i As Long
Dim j As Long
Dim nameField As String
Dim nameTable As String
Dim posTableNameSt As Long
Dim posTableNameEnd As Long
' join conditions start at ON
posAt = InStr(1, tsqlFROMpart, " ON ")
While posAt > 0
posStart = posAt + 4
' conditions last till JOIN or end of FROM part
posEnd = FirstAnyOf(tsqlFROMpart, posStart, " LEFT ## RIGHT ## INNER ## JOIN ## ON ", "##")
strConditions = Mid(tsqlFROMpart, posStart, posEnd - posStart + 1)
' conditions separated by AND or OR logical operators
strConditions = Replace(strConditions, " AND ", "##")
strConditions = Replace(strConditions, " OR ", "##")
arrConditions = Split(strConditions, "##")
For i = LBound(arrConditions) To UBound(arrConditions)
strCurrCond = arrConditions(i)
' condition can be made by = , < , > , <> , >= , <=
strCurrCond = Replace(strCurrCond, "=", "##")
strCurrCond = Replace(strCurrCond, ">", "##")
strCurrCond = Replace(strCurrCond, "<", "##")
strCurrCond = Replace(strCurrCond, "####", "##")
strCurrCond = unWrapWith(strCurrCond, "(", ")")
strParts = Split(strCurrCond, "##")
' target table can be on left side or right side
For j = 0 To 1
strParts(j) = Trim(strParts(j))
strParts(j) = Replace(strParts(j), "(", "") ' becase cutting
strParts(j) = Replace(strParts(j), ")", "") ' is not accurate
' name in this condition can be wrapped with [] or unwrapped
posTableNameSt = InStr(1, strParts(j), enameTargetTable)
If posTableNameSt <> 0 Then
posTableNameEnd = posTableNameSt + cLenTableEName
Else
posTableNameSt = InStr(1, strParts(j), nameTargetTable)
posTableNameEnd = posTableNameSt + cLenTableName
End If
If posTableNameSt > 0 Then
' found , so add to dictionary
nameField = Mid(strParts(j), posTableNameEnd + 1) ' +1 because of . between table name and field name
dictGROUPBYFields(nameField) = strParts(j)
Exit For
End If
Next j
Next i
posAt = InStr(posAt + 1, tsqlFROMpart, " ON ")
Wend
Dim tsqlSETpart As String
tsqlSETpart = GetInner(tsqlText, " SET ", " FROM ")
Dim arrSetExpressions() As String
Dim strCurrExpression As String
Dim strExprValue As String
Dim dictFieldsInExpressions As Dictionary
Dim posFieldNameEnd As Long
Dim dictTmp As Dictionary
Dim posEqualSign As Long
Dim strTmp As String
Dim tsqlNewSETpart As String
Set dictFieldsInExpressions = New Dictionary
dictFieldsInExpressions.CompareMode = TextCompare ' means Table.Fld = TaBlE.FlD
arrSetExpressions = SplitLineCall("SET " & tsqlSETpart)
For i = 1 To UBound(arrSetExpressions) ' skipped SET element
strCurrExpression = arrSetExpressions(i) ' whole part
posEqualSign = InStr(1, strCurrExpression, "=")
strExprValue = Trim(Mid(strCurrExpression, posEqualSign + 1))
' so look in expressions for table.field references and put them into dictionary if not from target table
posAt = InStr(1, strExprValue, ".")
While posAt > 0
' go right to find fields name
If Mid(strExprValue, posAt + 1, 1) = "[" Then
posFieldNameEnd = InStr(posAt + 2, strExprValue, "]")
Else
posFieldNameEnd = FirstAnyOf(strExprValue, posAt + 2, " #,#;#""#)#(#=#+#-#/#*")
End If
nameField = Mid(strExprValue, posAt + 1, posFieldNameEnd - posAt)
'go left to find table name
If Mid(strExprValue, posAt - 1, 1) = "]" Then
posTableNameSt = InStrRev(strExprValue, "[", posAt - 2)
Else
posTableNameSt = FirstAnyOfRev(strExprValue, posAt - 1, " #,#;#""#)#(#=#+#-#/#*") + 1
End If
nameTable = Mid(strExprValue, posTableNameSt, posAt - posTableNameSt)
' if we found not target table add to dictionary
If unWrapWith(nameTable, "[", "]") <> nameTargetTable Then
strTmp = Mid(strExprValue, posTableNameSt, posFieldNameEnd - posTableNameSt + 1)
If isEvaluationable(strTmp) Then
' do nothing it is just a number with point
Else
Set dictTmp = New Dictionary
dictTmp("nameTable") = nameTable
dictTmp("nameField") = nameField
dictTmp("expression") = strTmp
Set dictFieldsInExpressions(dictTmp("expression")) = dictTmp
Set dictTmp = Nothing
' and replace Table name to CTE
strExprValue = Left(strExprValue, posTableNameSt - 1) & "CTE" & Mid(strExprValue, posAt)
posAt = posAt + Len(nameTable) - 3
End If
End If
posAt = InStr(posAt + 1, strExprValue, ".")
Wend
strCurrExpression = Left(strCurrExpression, posEqualSign) & " " & strExprValue
arrSetExpressions(i) = strCurrExpression ' write back
tsqlNewSETpart = tsqlNewSETpart & " , " & strNL & strCurrExpression
Next i
tsqlNewSETpart = Mid(tsqlNewSETpart, 4 + Len(strNL))
Dim tsqlResult As String
Dim tsqlNewFROMpart As String ' 1
Dim tsqlNewONpart As String '7
Dim tsqlGROUPfields As String ' 2 & 6
Dim tsqlSUMfields As String
Dim tsqlWHEREpart As String
tsqlNewFROMpart = GetInner(tsqlText, " FROM ", ";", True)
tsqlWHEREpart = GetInnerEx(tsqlNewFROMpart, "WHERE ", "GROUP BY ", "HAVING ", "ORDER BY ", ";", "<EOL>")
If tsqlWHEREpart <> "" Then
tsqlWHEREpart = " WHERE " & tsqlWHEREpart
End If
tsqlGROUPfields = Join(dictGROUPBYFields.Items, " , ")
Dim varKey As Variant
Dim dictItem As Variant
For Each dictItem In dictFieldsInExpressions.Items
tsqlSUMfields = tsqlSUMfields & ", " & "SUM(" & dictItem("expression") & ") AS " & dictItem("nameField") & ""
Next dictItem
For Each varKey In dictGROUPBYFields.Keys
tsqlNewONpart = tsqlNewONpart & " AND " & "(" & enameTargetTable & "." & varKey & " = CTE." & varKey & ")"
Next varKey
tsqlNewONpart = Mid(tsqlNewONpart, 6)
tsqlResult = _
"WITH CTE AS (" & strNL & _
" SELECT " & strNL & _
" " & tsqlGROUPfields & strNL & _
" " & tsqlSUMfields & strNL & _
" FROM " & strNL & _
" " & tsqlNewFROMpart & strNL & _
" GROUP BY " & strNL & _
" " & tsqlGROUPfields & strNL & _
") " & strNL & _
"UPDATE " & strNL & _
" " & enameTargetTable & " " & strNL & _
"SET " & strNL & _
"" & tsqlNewSETpart & " " & strNL & _
"FROM " & strNL & _
" " & enameTargetTable & " " & strNL & _
" INNER JOIN " & strNL & _
" CTE " & strNL & _
" ON " & strNL & _
" " & tsqlNewONpart & strNL & _
"" & tsqlWHEREpart & strNL & _
";"
If Not fMultiLineOutput Then
tsqlResult = ReplaceAll(tsqlResult, " ", " ")
End If
Dim bIsResultValid As Boolean
'bIsResultValid = isValidTSQL(tsqlResult) ' check if we got goot TSQL
'If bIsResultValid Then
UpSizeUPDATEwithJOIN = """" & tsqlResult & """"
'Else
' UpSizeUPDATEwithJOIN = tsqlText
' Debug.Print , "!!U GOT bad: " & tsqlResult
'End If
End Function
I have a excel sheet with a column named sqlQueries.
Every cell has a set of queries to run.
I am able to run sumple queries using qtp
But the cells that have multiple statements like for e.g in cell(x,6) the below query is present:
"
Use LDatabase
Exec sp_DropObjectIfExists '#tempTable';
Select col1 into #tempTable from maintable;
Update #tempTable set colv=5
Select count(1) as totalCount from #tempTable
"
The above is just an e.g. and not the exact sql query.
This entire set is in a single excel sheet's cell.
I want this to be executed using Qtp.
Currently, what I am doing in qtp is:
Set objconnection = CreateObject("ADODB.Connection")
objconnection.open"provider=blah blah blah"
Set objrecordset= CreateObject("ADODB.Recordset")
ws.cells(x,6).select ''''the above sql queries set is in this cell
Sqlquery1= ws.cells(x,6).value
objrecordset.Open Sqlquery1. objconnection
Value1=objrecordset.Fields.Item(0)
For the Last line above I am getting error saying
"Items cannot be found in the collection corresponding to requestef name or ordinal"
I am assuming this is because there are multiple statements in a single cell which are to be excuted but only the first line that is "use LDatabase" is being executed. And not all the cell content.
Could you please help me execute the entire thing in a single shot.
Thanks!
Prefix your queries with SET NOCOUNT ON;. This will allow you to use temp tables and variables in your SQL statements.
The code below demonstates this. I've used early binding to make the code easier to read (Tools >> References >> Microsoft ActiveX Data Objects 2.8 Library).
Switch between these lines to test:
rs.Open QueryA, cn, adOpenForwardOnly, adLockReadOnly
rs.Open QueryB, cn, adOpenForwardOnly, adLockReadOnly
QueryA will fail. QueryB will return Jack.
' Demo of using SET NOCOUNT ON;.
' This option enabled the use of SQL vars and temp tables.
Sub Test()
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset
cn.Open "Driver={SQL Server};Server=YOUR-SEVER-NAME-HERE;Database=master;Trusted_Connection=Yes;"
' QueryA fails, while QueryB does not.
' Switch which line is commented out to test.
rs.Open QueryA, cn, adOpenForwardOnly, adLockReadOnly
'rs.Open QueryB, cn, adOpenForwardOnly, adLockReadOnly
' This line will raise an error with QueryA.
' This line will work with QueryB.
MsgBox rs.Fields(1).Value
rs.Close
cn.Close
End Sub
' Returns a sample query without NOCOUNT.
Public Function QueryA() As String
QueryA = " CREATE TABLE #ExampleA "
QueryA = QueryA & " ( "
QueryA = QueryA & " Id INT PRIMARY KEY, "
QueryA = QueryA & " Name VARCHAR(50) NOT NULL "
QueryA = QueryA & " ); "
QueryA = QueryA & ""
QueryA = QueryA & " INSERT INTO #ExampleA (Id, Name) "
QueryA = QueryA & " VALUES "
QueryA = QueryA & " (1, 'Jack'), "
QueryA = QueryA & " (2, 'Jill') "
QueryA = QueryA & " ; "
QueryA = QueryA & ""
QueryA = QueryA & " SELECT * FROM #ExampleA "
End Function
' Returns a sample query with NOCOUNT.
Public Function QueryB() As String
QueryB = " SET NOCOUNT ON; "
QueryB = QueryB & ""
QueryB = QueryB & " CREATE TABLE #ExampleA "
QueryB = QueryB & " ( "
QueryB = QueryB & " Id INT PRIMARY KEY, "
QueryB = QueryB & " Name VARCHAR(50) NOT NULL "
QueryB = QueryB & " ); "
QueryB = QueryB & ""
QueryB = QueryB & " INSERT INTO #ExampleA (Id, Name) "
QueryB = QueryB & " VALUES "
QueryB = QueryB & " (1, 'Jack'), "
QueryB = QueryB & " (2, 'Jill') "
QueryB = QueryB & " ; "
QueryB = QueryB & ""
QueryB = QueryB & " SELECT * FROM #ExampleA "
End Function
I've embedded the two versions of my query in a couple of, ugly, functions. They're hard to read but easy to share. Below is a clean version of the working query. Remove the first line for the non-working variant.
SET NOCOUNT ON;
CREATE TABLE #ExampleA
(
Id INT PRIMARY KEY,
Name VARCHAR(50) NOT NULL
);
INSERT INTO #ExampleA (Id, Name)
VALUES
(1, 'Jack'),
(2, 'Jill')
;
SELECT * FROM #ExampleA;
I am trying to get a form setup to launch various reports based on different criteria and I am having problems getting one of the reports that is a GroupBy/Count/Sum based SQL Data source to work between 2 unbound textboxes serving as a FromDate and a ToDate.
VBA script - calling report from form (frmRptFeedback):
Private Sub cmdPrint_Click()
If Not chkPrintPreview Then
Set Application.Printer = Application.Printers.Item(cboPrinter.Value)
End If
Dim strCondition As String
Dim strFromDate As String
Dim strToDate As String
strFromDate = txtFromDate.Value
strToDate = txtToDate.Value
Select Case opgOptions
Case 1 ' Feedback By Employee
If IsNull(cboEmployee.Value) Then
strCondition = "DateSubmitted BETWEEN '" & strFromDate & "' AND '" & strToDate & "'"
Else
strCondition = "RespEmp = '" & cboEmployee.Value & "' AND DateSubmitted BETWEEN '" & _
strFromDate & "' AND '" & strToDate & "'"
End If
Call OpenReport("rptFeedbackByEmp", IIf(chkPrintPreview, acViewPreview, acViewNormal), strCondition)
Case 2 ' Feedback By Team
If IsNull(cboTeam.Value) Then
strCondition = "DateSubmitted BETWEEN '" & strFromDate & "' AND '" & strToDate & "'"
Else
strCondition = "EmpType = '" & cboTeam.Value & "' AND DateSubmitted BETWEEN '" & _
strFromDate & "' AND '" & strToDate & "'"
End If
Call OpenReport("rptFeedbackByTeam", IIf(chkPrintPreview, acViewPreview, acViewNormal), strCondition)
Case 3 ' Feedback By Project #
If IsNull(txtProjectID) Then
strCondition = "DateSubmitted BETWEEN '" & strFromDate & "' AND '" & strToDate & "'"
Else
strCondition = "ProjectID = " & txtProjectID & "AND DateSubmitted BETWEEN '" & _
strFromDate & "' AND '" & strToDate & "'"
End If
Call OpenReport("rptFeedbackByProject", IIf(chkPrintPreview, acViewPreview, acViewNormal), strCondition)
End Select
If Not chkPreview Then
Set Application.Printer = Nothing
End If
End Sub
SQL query - initially pulling data into main SQL View (vueRptFeedback):
SELECT f.FeedbackID, f.BFID, bf.ProjectID, p.ProjectName, e2.Name AS PM, e1.Name AS RespEmp,
et.Description AS EmpType, f.SubByInits, f.DateSubmitted, f.QtyIssues,
f.EstHoursImpact, f.PlusDelta, f.Notes, f.HowResolved
FROM dbo.tblEmployee e2
INNER JOIN dbo.tblProject p
INNER JOIN dbo.tblBookingForm bf
ON p.ProjectID = bf.ProjectID
ON e2.EmployeeID = p.Scope_PM_EmployeeID
RIGHT OUTER JOIN dbo.tblEmployeeType et
INNER JOIN dbo.tblEmployee e1
ON et.EmployeeTypeID = e1.EmployeeTypeID
INNER JOIN dbo.tblFeedback f
ON e1.EmployeeID = f.ResponsibleEmpID
ON bf.BookingFormID = f.BFID
SQL query - current recordsource for report by Project ID (vueRptFeedbackByProject):
SELECT ProjectID, ProjectName, RespEmp, COUNT(FeedbackID) AS CountReports,
SUM(QtyIssues) AS SumIssues, SUM(EstHoursImpact) AS SumHours
FROM vueRptFeedback
WHERE (DateSubmitted
BETWEEN CONVERT(DATETIME, [Forms]![frmRptFeedback]![txtFromDate], 102)
AND CONVERT(DATETIME, [Forms]![frmRptFeedback]![txtToDate], 102))
GROUP BY ProjectID, RespEmp, ProjectName, DateSubmitted
ORDER BY ProjectID, RespEmp
I know my problem is in the WHERE clause as when I take it out, the report pulls fine but with all records, not the ones between those two dates. Once I can get the report to pull between the txtFromDate and txtToDate, I will probably need to change the OpenReport() to pass the txtFromDate and txtToDate as parameters instead of a Between X and Y, but I keep getting tripped up by syntax on the Recordsource of the report.
Fundamentally, you are conflating two SQL dialects - SQL Server SQL and MS Access SQL. There is no CONVERT() function in Access SQL syntax which appears to be the engine running the recordsource of the report and not the pass-through query, vueRptFeedback, run by MSSQL.
Consider using FORMAT() to align dates to ANSI datetime format: YYYY-MM-DD:
SELECT ProjectID, ProjectName, RespEmp, COUNT(FeedbackID) AS CountReports,
SUM(QtyIssues) AS SumIssues, SUM(EstHoursImpact) AS SumHours
FROM vueRptFeedback
WHERE (DateSubmitted
BETWEEN FORMAT([Forms]![frmRptFeedback]![txtFromDate], "YYYY-MM-DD")
AND FORMAT([Forms]![frmRptFeedback]![txtToDate], "YYYY-MM-DD"))
GROUP BY ProjectID, RespEmp, ProjectName, DateSubmitted
ORDER BY ProjectID, RespEmp
On the VBA side, you can still use Format() as many of Access's SQL functions derived from VBA functions (possibly, this is the reason Access SQL differs from its other RDMS counterparts who adhere to ANSI more due to the need to stay compatible in MS Office VBA context):
Dim strFromDate As String
Dim strToDate As String
strFromDate = Format(txtFromDate.Value, "YYYY-MM-DD")
strToDate = Format(txtToDate.Value, "YYYY-MM-DD")
...
I am attempting to write the results of a query in specific spaces on a spreadsheet. The SQL creates temporary tables for use during the query and then drops them at the end. Is this the cause of my problem? I have posted my source code below. The error is thrown on line 530. Is there a better way to do this?
410 With wsSheet
420 Set rnStart = Sheets("Discharge Information").Range("Q51")
430 End With
440 strSQL = "create table #encounters ( DischargeKey int,EncounterID varchar(25)) insert into #encounters " & _
"SELECT top 30 dischargekey,encounternumber from discharges order by dischargedate desc " & _
"CREATE TABLE #icd9_poa(DischargeKey int,ICD9 nvarchar(max),POA nvarchar(max)) " & _
"DECLARE #i int, #f int SET #i = 1 SET #f = ( " & _
"SELECT REPLACE(column_name,'icd9_POA_','') FROM information_schema.Columns WHERE column_name LIKE 'icd9_POA_%' AND table_name = 'temp_discharge' AND ordinal_position IN ( " & _
"SELECT Max (ordinal_position) FROM information_schema.Columns " & _
"WHERE column_name LIKE 'icd9_POA_%' AND table_name = 'temp_discharge')) " & _
"WHILE #i <= #f " & _
"BEGIN IF #i=1 " & _
"BEGIN INSERT INTO #icd9_poa " & _
"SELECT d.DischargeKey,i.icd9code,poa.poa " & _
"FROM discharges d " & _
"inner join #encounters e on e.dischargekey = d.dischargekey INNER join icd9diagnosesbridge icb on icb.discharge=d.dischargekey INNER join icd9diagnoses i on icb.icd9 = i.icd9key INNER join presentonadmission poa on icb.presentonadmission = poa.poakey " & _
"WHERE icb.Icd9Sequence = 1 End " & _
"IF #I>1 BEGIN " & _
"Update t SET t.Icd9 = t.Icd9 + ', '+i.Icd9Code,t.poa = t.poa + ', '+ poa.poa " & _
"FROM #Icd9_poa t" & _
"INNER JOIN Discharges d ON (t.DischargeKey=d.DischargeKey) INNER JOIN Icd9DiagnosesBridge icb ON (icb.Discharge=d.DischargeKey) INNER JOIN Icd9Diagnoses i ON (icb.Icd9=i.icd9Key) INNER JOIN PresentOnAdmission poa ON (icb.PresentOnAdmission=poa.PoaKey) " & _
"WHERE icb.Icd9Sequence=#i End " & _
"SET #i = #i + 1 End " & _
"select icd9, poa from #icd9_poa " & _
"drop table #icd9_poa " & _
"drop table #encounters "
450 Set cnt = New ADODB.Connection
460
470 With cnt
480 .CursorLocation = adUseClient
490 .Open ConnectionString
500 .CommandTimeout = 0
510 Set rst = .Execute(strSQL)
520 End With
530 rnStart.CopyFromRecordset rst
At a very quick look, I would try this method:
RETURNS #icd9_poa TABLE (
DischargeKey int,
ICD9 nvarchar(max),
POA nvarchar(max))
AS
BEGIN
... then insert your SQL (remembering that icd9_poa is already defined)
END
Don't bother with dropping temp tables - SQL Server will remove them as soon as your procedure finishes running
I can't test it fully, as I don't have your data, but this is a method to return a recordset from an SQL procedure.
Deleting the temp tables is not necessary and will not be causing your error.
It looks like your connection has closed by the time you call "CopyFromRecordSet", try moving that call into the "With" block.
I have 2 tables, TableA and TableB. IMAT_PRIORITY_ID is primary key in TableA.
How can I get the value of IMAT_PRIORITY_ID in a textbox after inserting into TableA?
strSQL1 = "INSERT TableA (IMAT_PRIORITY_ID,JOB_NO,BATCH_NO) VALUES (SQ_PRIOTITY_ID.nextval," & JOB_NO.Text & "','" & BATCH_NO.Text & "')"
With adoCommand
.ActiveConnection = adoconn
.CommandType = adCmdText
.CommandText = strSQL1
.Prepared = True
.Execute , , adCmdText + adExecuteNoRecords
End With
strSQL1 = "INSERT TableB (ISBN_SERIAL_NO,IMAT_PRIORITY_ID,ISBN) VALUES (ISBN_SERIAL_NO.NEXTVAL,'" & IMAT_PRIORITY_ID.Text & "','" & ISBN.Text & "')"
With adoCommand
.ActiveConnection = adoconn
.CommandType = adCmdText
.CommandText = strSQL1
.Prepared = True
.Execute , , adCmdText + adExecuteNoRecords
End With
To get the last identity (PRIMARY KEY) generated from the insert statement you can query it as follows..
strSQL1 = "INSERT TableA (IMAT_PRIORITY_ID,JOB_NO,BATCH_NO) VALUES (SQ_PRIOTITY_ID,JOB_NO,BATCH_NO) VALUES (SQ_PRIOTITY_ID.nextval," & JOB_NO.Text & "','" & BATCH_NO.Text & "');SELECT SCOPE_IDENTITY()"
You can find more details over here