Using a SELECT statement to return a row where a DateTime column = variable of type Date? - sql

I am using OleDb, trying to do this:
Dim d as Date = DateSerial(Year(rptDate), Month(rptDate), 1 - 1)
Dim conn as OleDbConnection = new OleDbConnection(connStr)
Dim cm as OleDbCommand = new OleDbCommand()
conn.Open()
cm.Connection = conn
cm.CommandText = "SELECT * FROM history WHERE ReportDate = " & d
Okay, so I know it returns 1 row because I'm staring at it in SQL Server. Here is what I've tried so far for the query in the last line, none work:
"SELECT * FROM history WHERE ReportDate = " & d
"SELECT * FROM history WHERE ReportDate = " & d.toString("G")
"SELECT * FROM history WHERE ReportDate = '" & d & "'"
"SELECT * FROM history WHERE ReportDate = '" & d.toString("G") & "'"
"SELECT * FROM history WHERE ReportDate = '#" & d & "#'"
"SELECT * FROM history WHERE ReportDate = #" & d & "#" 'These last 2 with toString
I have also tried:
cm.CommandText = "SELECT * FROM history WHERE ReportDate = ?"
cm.Parameters.Add(d)
cm.CommandText = "SELECT * FROM history WHERE ReportDate = ?"
cm.Parameters.Add(d.toString("G"))
cm.CommandText = "SELECT * FROM history WHERE ReportDate = '?'"
cm.Parameters.Add(d.toString("G"))
cm.CommandText = "SELECT * FROM history WHERE ReportDate = '?'"
cm.Parameters.Add(d)
Clearly I am missing something here, help? I know that d is the same date as the one in SQL server, specifically 3/31/2011 12:00:00 AM.

Write
cm.CommandText = "SELECT * FROM history WHERE ReportDate = ?"
cm.Parameters.AddWithValue("ParamName", d)
Depending on your provider, you may need to use named parameters:
cm.CommandText = "SELECT * FROM history WHERE ReportDate = #date"
cm.Parameters.AddWithValue("date", d)

Try using another date format in your SQL such as:
Cm.CommandText = "SELECT * FROM history WHERE ReportDate = '" & d.toString("mm/dd/yyyy") & "'"

Did you mean to create your date variable (d) as the day before the rptDate value (ie. with a day of zero (1-1)) ?
This (below) will get you your record (assuming the record has no time part).
SELECT * FROM history WHERE ReportDate = '" & d.toString("dd-MMM-yyyy") & "'"
(The explicit date format is unambiguous, whereas "G" is not.)
...or...
cm.CommandText = "SELECT * FROM history WHERE ReportDate = #date"
cm.Parameters.AddWithValue("#date", d)

Your query as stated is asking "give me all the entries for exactly midnight on this date".
Something like this should hopefully work:
cm.CommandText = "DECLARE #MyDate DATETIME; SET #MyDate = ?; SELECT * FROM history WHERE ReportDate >= #MyDate AND ReportDate < DateAdd(day,1,#MyDate);"
cm.Parameters.Add(d)
This will return all entries on or after midnight of the date and before midnight of the next day.

Related

Dynamic Calculated Field in VBA Access

I'm trying to add a field into an existing table. The field is calculated using two variables 'myPrice', which is the price of a record at a certain date, and 'previousPrice', which is the price of the same part from the first record, only a from the month previous. I'm using a loop to iterate through the entire recordset of prices, thereby altering the two variables each time. My code is as follows:
Function priceDifference()
Dim currentPrice As Currency
Dim previousPrice As Currency
Dim recordDate As Date
Dim previousDate As Date
Dim dbsASSP As DAO.Database
Dim priceTable As DAO.TableDef
Dim diffFld As DAO.Field2
Dim rstCurrentPrice As DAO.Recordset
Dim rstPreviousPrice As DAO.Recordset
Dim PN As String
Set dbsASSP = CurrentDb
strSQL = "SELECT * FROM qryPrice"
Set rstCurrentPrice = dbsASSP.OpenRecordset(strSQL, dbOpenDynaset)
Set priceTable = dbsASSP.TableDefs("tblPrice")
Set diffFld = priceTable.CreateField("Difference", dbCurrency)
If Not (rstCurrentPrice.EOF) Then
rstCurrentPrice.MoveFirst
Do Until rstCurrentPrice.EOF = True
PN = rstCurrentPrice![P/N]
recordDate = rstCurrentPrice![myDate]
previousDate = Format(DateAdd("m", -1, recordDate), "M 1 YYYY")
myPrice = rstCurrentPrice!Price
strPreviousSQL = "SELECT * FROM qryPrice WHERE [MyDate] = #" & previousDate & "# AND [Type] = 'Net Price' AND [P/N] = " & PN & ""
Set rstPreviousPrice = dbsASSP.OpenRecordset(strPreviousSQL, dbOpenDynaset)
myCodeName = rstCurrentPrice!CodeName
If DCount("[P/N]", "qryPrice", "[MyDate] = #" & previousDate & "# And [P/N] = " & PN) <> 0 Then
previousPrice = rstPreviousPrice!Price
Else
previousPrice = myPrice
End If
rstCurrentPrice.MoveNext
Loop
Else
MsgBox "Finished looping through records."
End If
diffFld.Expression = myPrice - previousPrice
rstCurrentPrice.Close
rstPreviousPrice.Close
priceTable.Fields.Append diffFld
End Function
Syntactically, it works. The calculated field, however, does not give me the correct values and I cannot figure out why, although I imagine it has something to do with the dynamic formula.
Any help is appreciated. Thanks!!
Your code can't work as you append a number to the field instead of a formula, but you should avoid calculated fields
Use a query:
SELECT
nPrice.[P/N],
nPrice.Price,
nPrice.MyDate,
oPrice.MyDate,
nPrice.Price-Nz(oPrice.Price,nPrice.Price) AS diff
FROM (
SELECT
[P/N],
Price,
MyDate,
Format(DateAdd("m",-1,MyDate),"yyyymm") as previousMonthYear
FROM
tblPrice) AS nPrice
LEFT JOIN (
SELECT
[P/N],
Price,
MyDate,
Format(MyDate,"yyyymm") AS monthYear
FROM
tblPrice) AS oPrice
ON
nPrice.[P/N] = oPrice.[P/N]
AND nPrice.previousMonthYear = oPrice.monthYear
This calculates the difference dynamic and you don't need to store it.
I assume there is max one price per month, otherwise you need to filter the subqueries or just calculate the difference to the last price before.
If the query is too slow ([P/N] and MyDate need an index) , you can still use it to update a field the table tblPrice, but this has to be updated every time a price is updated or inserted in tblPrice
I think you can avoid your code loop by using this query
SELECT A.qryPrice, A.MyDate, B.qryPrice, B.MyDate
FROM qryPrice A LEFT OUTER JOIN qryPrice B
ON A.[P/N] = B.[P/N]
AND B.MyDate = DATEADD(month, -1, A.MyDate)

(Ms Access) Row_Number() Over Partition

How can I convert the row_number() function with an over partition on MS ACCESS? What I want to achieve is:
from this table:
ID | EntryDate
10 | 2016-10-10
10 | 2016-12-10
10 | 2016-12-31
10 | 2017-01-31
10 | 2017-03-31
11 | 2015-01-31
11 | 2017-01-31
To this output, showing only the top 3 latest of each ID:
ID | EntryDate
10 | 2016-12-31
10 | 2017-01-31
10 | 2017-03-31
11 | 2015-01-31
11 | 2017-01-31
On SQL Server, i can achieved this using the following code:
select T.[ID],
T.[AptEndDate],
from (
select T.[ID],
T.[AptEndDate],
row_number() over(partition by T.[ID] order by T.[AptEndDate] desc) as rn
from Table1 as T
) as T
where T.rn <= 3;
Consider a count correlated subquery which can work in any RDBMS.
select T.[ID], T.[EntryDate]
from
(select sub.[ID],
sub.[EntryDate],
(select count(*) from Table1 c
where c.ID = sub.ID
and c.[EntryDate] >= sub.[EntryDate]) as rn
from Table1 as sub
) as T
where T.rn <= 3;
It might be simpler and faster to use Top n - as you mention yourself:
Select T.[ID], T.[EntryDate]
From Table1 As T
Where T.[EntryDate] In
(Select Top 3 S.[EntryDate]
From Table1 As S
Where S.[ID] = T.[ID]
Order By S.[EntryDate] Desc)
Order By T.[ID] Asc, T.[EntryDate] Asc
Anything using the OVER clause is something known as a Windowing Function. Unfortunately, MS Access does not have support for Windowing Functions.The easiest solution in this case may be to back to VBA code :(
Public Const tableName As String = "[TransactionalData$]"
Public Const parentId As String = "parentId"
Public Const elementId As String = "Id"
Public Const informationalField As String = "Label"
Sub TransactionalQuery(Optional ByVal Id As Integer = 0)
Dim rs As New ADODB.Recordset, cn As New ADODB.Connection
Dim sqlString As String
''' setup the connection to the current Worksheet --- this can be changed as needed for a different data source, this example is for EXCEL Worksheet
cn.Open ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & ";Extended Properties='Excel 12.0 Macro;HDR=YES;IMEX=1'")
'''' Alternate method for the query
sqlString = "SELECT ParentId, Rank() OVER(PARTITION BY ParentId ORDER BY Label) , vlu.Id, vlu.Label FROM [TransactionalData$] var LEFT JOIN [TransactionalData$] vlu ON vlu.Id=var.ParentId"
''' will need to change the TableName (TransactionalData$]
sqlString = "SELECT DISTINCT " & elementId & " FROM " & tableName & " WHERE " & parentId & " = " & Id
rs.Open sqlString, cn, adOpenStatic, adLockReadOnly
'' Start collecting the SQL UNIONs to run at the end
sqlString = ""
Do While Not rs.EOF
'' Add current Element to the UNION
sqlString = sqlString & "SELECT * FROM " & tableName & " WHERE " & elementId & " = " & rs.Fields(elementId) & " UNION " & vbCrLf
'' Add all children element to the UNION
sqlString = sqlString & subQuery(cn, rs.Fields(elementId))
rs.MoveNext
Loop
rs.Close
'''Debug.Print sqlString
''' Remove the extra UNION keyword at the end
sqlString = Left(sqlString, Len(sqlString) - 8)
''' Exectue the built query
rs.Open sqlString, cn, adOpenStatic, adLockReadOnly
''Do While Not rs.EOF
'' Debug.Print rs.Fields(elementId) & ", " & rs.Fields(informationalField)
'' rs.MoveNext
''Loop
End Sub
Function subQuery(cn As ADODB.Connection, Id As Integer) As String
Dim sqlString As String
Dim subSqlString As String, rs As New ADODB.Recordset
'' Create a list of children for the current element
sqlString = "SELECT DISTINCT " & elementId & " FROM " & tableName & " WHERE " & parentId & " = " & Id
rs.Open sqlString, cn, adOpenStatic, adLockReadOnly
'' start the SQL for current elements children
sqlString = ""
Do While Not rs.EOF
''' add in the current element to the UNION
sqlString = sqlString & "SELECT * FROM " & tableName & " WHERE Id = " & rs.Fields(elementId) & " UNION " & vbCrLf
''' recursively find additional children for the current element
sqlString = sqlString & subQuery(cn, rs.Fields(elementId))
rs.MoveNext
Loop
rs.Close
''' return the SQL for the current element and all its children
subQuery = sqlString
End Function

syntax error in string in query in VBA access

I get 3075 error running this line in vba access:
Dim sqlMZG As String
sqlMZG = "SELECT MAZeitenGesamt.* Where MAZeitenGesamt.MA = 'JPA' FROM MAZeitenGesamt;"
Where JPA is a constant value. I tried the following forms and none of them worked.
SELECT MAZeitenGesamt.* Where MAZeitenGesamt.[MA] = '" & "JPA" & "' FROM MAZeitenGesamt;
SELECT MAZeitenGesamt.* Where MAZeitenGesamt.MA = '" & "JPA" & "' FROM MAZeitenGesamt;
SELECT MAZeitenGesamt.* Where MAZeitenGesamt.MA = ""JPA"" FROM MAZeitenGesamt;
SELECT MAZeitenGesamt.* Where MAZeitenGesamt.MA = \"JPA\" FROM MAZeitenGesamt;
SELECT MAZeitenGesamt.* Where MAZeitenGesamt.MA = \'JPA\' FROM MAZeitenGesamt;
Any ideas?
I'd recommend you use a parameter rather than quoting a literal. That said, #gizlmeier is right, in that your syntax is wrong to begin with.
Dim sqlMZG As String
sqlMZG = "parameters [MAParam] text; " & _
"SELECT MAZeitenGesamt.* FROM MAZeitenGesamt Where MAZeitenGesamt.MA = [MAParam];"
From there, when you create your query you can set the value for the parameter:
Set qry = CurrentDb.CreateQueryDef("GetMaz", sqlMZG)
qry.Parameters("MAParam") = JPA
No messy quoting to worry about and such.

Identical datatable 2 columns merging and summing one column in vb.net

I have 5 datatables which having each 3 columns (ID, Brand, Quanitiy) to derive the opening, purchase, sales and closing stock. The First 3 datatables should be merged and sum up to derive the opening stock as on given period. 4 th datatable is for Purchases done for the given period. The last one Datatable is for Sales done for the given period.
Here is my question:
How can i merge the 3 datatables and using the first 2 columns and summing the values?
How can i use the tables in crystal reports?
My code is :
Dim con As New ClassConnection
If con.Conn.State = ConnectionState.Closed Then con.Conn.Open()
'To get Opening Stock in Full Quantity
Dim sql As String = "SELECT tblBrand.B_ID AS ID, tblBrand.B_Name AS Brand," & _
" Sum (tblOp_Details.Net_Qty) AS Quantity FROM tblOp_Stock INNER JOIN (tblBrand INNER JOIN" & _
" tblOp_Details ON tblBrand.B_ID = tblOp_Details.B_ID) ON tblOp_Stock.Stk_ID = tblOp_Details.Stk_ID" & _
" WHERE tblOp_Stock.God_ID = #GID GROUP BY tblBrand.B_ID, tblBrand.B_Name"
'To get Purchases < start date and adding to the opening stock
Dim sql1 As String = "SELECT tblBrand.B_ID AS ID, tblBrand.B_Name AS Brand," & _
" Sum (tblPur_Details.Net_Qty) AS Quantity FROM tblPurchase INNER JOIN (tblBrand INNER JOIN" & _
" tblPur_Details ON tblBrand.B_ID = tblPur_Details.B_ID) ON tblPurchase.Pur_ID = tblPur_Details.Pur_ID" & _
" WHERE tblPurchase.God_ID = #GID AND tblPurchase.Rec_Date < #SDate GROUP BY tblBrand.B_ID, tblBrand.B_Name"
'To get Sales < Start date and subtracting to the above
Dim sql2 As String = "SELECT tblBrand.B_ID AS ID, tblBrand.B_Name AS Brand," & _
" Sum (tblSales_Details.Net_Qty) AS Quantity FROM tblSales INNER JOIN (tblBrand INNER JOIN" & _
" tblSales_Details ON tblBrand.B_ID = tblSales_Details.B_ID) ON tblSales.Sale_ID = tblSales_Details.Sale_ID" & _
" WHERE tblSales.God_ID = #GID AND tblSales.Sale_Date < #SDate GROUP BY tblBrand.B_ID, tblBrand.B_Name"
'The above 3 condition is for deriving opening stock as on given date
'To get Purchases >= Start Date and <= Start Date
Dim sql3 As String = "SELECT tblBrand.B_ID AS ID, tblBrand.B_Name AS Brand," & _
" Sum(tblPur_Details.Net_Qty) AS Quantity FROM tblBrand INNER JOIN (tblPurchase INNER JOIN" & _
" tblPur_Details ON tblPurchase.Pur_ID = tblPur_Details.Pur_ID) ON tblBrand.B_ID = tblPur_Details.B_ID" & _
" WHERE tblPurchase.God_ID = #GID And tblPurchase.Rec_Date >= #SDate And tblPurchase.Rec_Date" & _
" <= #EDate GROUP BY tblBrand.B_ID, tblBrand.B_Name"
'The above condition is for deriving Purchases as on given date
'To get Sales >= Start Date and <= Start Date
Dim sql4 As String = "SELECT tblBrand.B_ID AS ID, tblBrand.B_Name AS Brand," & _
" Sum(tblSales_Details.Net_Qty) AS Quantity FROM tblBrand INNER JOIN (tblSales INNER JOIN" & _
" tblSales_Details ON tblSales.Sale_ID = tblSales_Details.Sale_ID) ON tblBrand.B_ID = tblSales_Details.B_ID" & _
" WHERE tblSales.God_ID = #GID And tblSales.Sale_Date >= #SDate And tblSales.Sale_Date <= #EDate" & _
" And tblSales_Details.S_Active = #SAct GROUP BY tblBrand.B_ID, tblBrand.B_Name"
'The above condition is for deriving Sales as on given date
Dim da As New OleDb.OleDbDataAdapter(sql, con.Conn)
Dim da1 As New OleDb.OleDbDataAdapter(sql1, con.Conn)
Dim da2 As New OleDb.OleDbDataAdapter(sql2, con.Conn)
Dim da3 As New OleDb.OleDbDataAdapter(sql3, con.Conn)
Dim da4 As New OleDb.OleDbDataAdapter(sql4, con.Conn)
da.SelectCommand.Parameters.AddWithValue("#GID", Me.stBar_G_ID.Text)
da1.SelectCommand.Parameters.AddWithValue("#GID", Me.stBar_G_ID.Text)
da1.SelectCommand.Parameters.AddWithValue("#SDate", Me.dtpStart.ToString)
da2.SelectCommand.Parameters.AddWithValue("#GID", Me.stBar_G_ID.Text)
da2.SelectCommand.Parameters.AddWithValue("#SDate", Me.dtpStart.ToString)
da3.SelectCommand.Parameters.AddWithValue("#GID", Me.stBar_G_ID.Text)
da3.SelectCommand.Parameters.AddWithValue("#SDate", Me.dtpStart.ToString)
da3.SelectCommand.Parameters.AddWithValue("#EDate", Me.dtpEnd.ToString)
da4.SelectCommand.Parameters.AddWithValue("#GID", Me.stBar_G_ID.Text)
da4.SelectCommand.Parameters.AddWithValue("#SDate", Me.dtpStart.ToString)
da4.SelectCommand.Parameters.AddWithValue("#EDate", Me.dtpEnd.ToString)
da4.SelectCommand.Parameters.AddWithValue("#SAct", "Yes")
Dim dt As New DataTable
Dim dt1 As New DataTable
Dim dt2 As New DataTable
Dim dt3 As New DataTable
Dim dt4 As New DataTable
Ignoring the fact that such operations should be done in the database instead of memory, you can use Linq-To-DataSet which is a subset of Linq-To-Objects.
If you want to concatenate the three tables, group by ID + Brand to get the sum of Quantity:
Dim allRows = dt1.AsEnumerable().Concat(dt2.AsEnumerable()).Concat(dt3.AsEnumerable())
Dim query = From row In allRows
Let GroupColumns = New With {
.Id = row.Field(Of Int32)("Id"),
.Brand = row.Field(Of String)("Brand")
}
Group row By GroupColumns Into Group
Select New With {
.Id = GroupColumns.Id,
.Brand = GroupColumns.Brand,
.SumQuantity = Group.Sum(Function(row) row.Field(Of Int32)("Quantity"))
}
Fill the merged table from the query:
Dim dt As DataTable = dt1.Clone() ' empty, same columns
For Each x In query
Dim row = dt.Rows.Add()
row.SetField("Id", x.Id)
row.SetField("Brand", x.Brand)
row.SetField("Quantity", x.SumQuantity)
Next

adding results of query against datatable to a column in another datatable in visual basic

Problem: I have populated a datatable using a query on a sql server database. The query is:
Select ID, startDate, codeID, Param,
(select top 1 startDate from myTable
where ID='" & ID & "' and Param = mt.param and codeID = 82 and startDate >= '" & startDate & "' and startDate >=mt.startDate
ORDER BY startDate)endTime,
from myTable mt where ID = '" & ID & "'
AND (startDate between '" & startDate & "' AND '" & endDate & "' AND (codeID = 81))
I want a new column called duration that will be the difference between endTime and startDate in milliseconds. I can't just add another subquery to the above query since the endTime column didn't exist until the subquery was ran.
So, is there a way to maybe run the first query to populate the datatable, then run a query like:
Select DateDiff(ms,endTime,startDate)
On its own and add its results to a new column in my datatable?
You can always nest that in another query:
select *, datediff(ms, startDate, endTime)
from (
<your existing query here>
) t
And while I'm here, it seems you need a lesson in parameterized queries:
Dim result As New DataTable
Dim Sql As String = _
"SELECT *, datediff(ms, startDate, endTime) FROM (" & _
"SELECT ID, startDate, codeID, Param, " & _
"(select top 1 startDate from myTable " & _
"where ID= #ID and Param = mt.param and codeID = 82 and startDate >= #startDate and startDate >=mt.startDate " & _
"ORDER BY startDate) endTime " & _
" FROM myTable mt " & _
" WHERE ID = #ID AND startDate between #startDate AND #endDate AND codeID = 81" & _
") t"
Using cn As New SqlConnection("connection string"), _
cmd As New SqlCommand(sql, cn)
cmd.Parameters.Add("#ID", SqlDbType.VarChar, 10).Value = ID
cmd.Parameters.Add("#startDate", SqlDbType.DateTime).Value = Convert.ToDateTime(startDate)
cmd.Parameters.Add("#endDate", SqlDbType.DateTime).Value = Convert.ToDateTime(endDate)
cn.Open()
Using rdr = cmd.ExecuteReader()
result.Load(rdr)
rdr.Close()
End Using
End Using