How do I access multiple records from the same table using SQLDataAdapter? - sql

This almost works. I get an error at the last line that looks like it's complaining about the C1 reference. Is there a simple way around this? There is nothing wrong with the query or connection.
Dim CmdString As String
Dim con As New SqlConnection
Try
con.ConnectionString = PubConn
CmdString = "select * from " & PubDB & ".dbo.Suppliers as S " & _
" join " & PubDB & ".dbo.Address as A" & _
" on S.Supplier_Address_Code = A.Address_IDX" & _
" join " & PubDB & ".dbo.Contacts as C1" & _
" on S.Supplier_Contact1 = C1.Contact_IDX" &
" join " & PubDB & ".dbo.Contacts as C2" & _
" on S.Supplier_Contact2 = C2.Contact_IDX" &
" WHERE S.Supplier_IDX = " & LookupIDX
Dim cmd As New SqlCommand(CmdString)
cmd.Connection = con
con.Open()
Dim DAdapt As New SqlClient.SqlDataAdapter(cmd)
Dim Dset As New DataSet
DAdapt.Fill(Dset)
con.Close()
With Dset.Tables(0).Rows(0)
txtAddress1.Text = .Item("Address1").ToString
txtAddress2.Text = .Item("Address2").ToString
txtSupplierName.Text = .Item("Address_Title").ToString
txtAttn.Text = .Item("Attn").ToString
txtBusinessPhone1.Text = .Item("C1.Contact_Business_Phone").ToString

You would not include the "C1" table alias as part of your column name. It will be returned from your query as Contact_Business_Phone.
For accessing multiple rows you could use the indexer as you are in the example above "Rows(0)" by placing your With block into a For loop and accessing the "Rows(i)" with your loop variable. However, this would not help much as your are assigning this to individual text boxes, so you'd only see the last value on your page/screen.

The alias C1 is used by SQL Server and is not persisted to the result set. Have you taken this query into SQL Management Studio to see the results?
Since you requested all columns (*) and joined to the Contacts table twice, you'll end up with duplicate column names in the result. For example, if the Contacts table has a LastName field, you'll end up with TWO LastName columns in your result.
I haven't tried to duplicate this in my local environment, but I can't imagine the data adapter is going to like having duplicate column names.
I recommend specifically including the columns you want to return instead of using the *. That's where you'll use the alias of C1, then you can rename the duplicate columns using the AS keyword:
SELECT C1.LastName AS [Supplier1_LastName],
C2.LastName AS [Supplier2_LastName],
...
This should solve your problem.
Good Luck!

You should only be pulling back the columns that you're in fact interested in, as opposed to *. It's sort of hard to tell exactly what data exists in which tables since you're pulling the full set, but at a quick guess, you'll want in your select statement to pull back A.Address1, A.Address2, A.AddressTitle, ?.Attn (not sure which table this actually derives from) and C1.Contact_Business_Phone. Unless you actually NEED the other fields, you're much better off specifying the individual fields in your query, besides having the possible duplicate field issue that you're running into here, it can also be a significant performance hit pulling everything in. After you clean up the query and only pull in the results you want, you can safely just reference them the way you are for the other fields, without needing a table alias (which as others have pointed out, isn't persisted to the result set anyways).

Related

Access Subform SourceObject Set to Query updated with SQL - Column Order and Width?

I have an Access form with different functions users can do. They are pulling lists of data, all from 1 table. Based on different filters or operations they want to do, I dynamically construct the SQL, use that to update the query defs of a query, and then set the subform object to that updated query. The problem is that the one I update the subform source object to the query, I need the columns that show to be in the order of the query.
This is the code I use, at different points of use on the form, depending on if they are interacting with a combo box, entering a filter into a textbox control on the main form, and I use similar code to set the default sql/query defs on load of the form. Why don't the columns always show in the same order as the sql that was updated to the query's definition?
Dim fsql As String
fsql = "SELECT table1.field1, table1.field2, table1.field3, table1.field4, table1.field5, table1.field6, table1.field7 " & _
"FROM tblVFileImport "
If Nz(Me.cboFilterA, "") = "" Then
fsql = fsql & "ORDER BY table1.field2, table1.field3 "
Else
fsql = fsql & "WHERE table1.field6 = '" &Me.cboFilterA & "' "
fsql = fsql & "ORDER BY table1.field4, table1.field5 "
Me.cmdExtrabutton.Visible = True
End If
CurrentDb.QueryDefs("qrySubformSpecs").SQL = fsql
Forms!frmDoStuff.Form.frmDoStuff_SubResults.SourceObject = ""
Forms!frmDoStuff.Form.frmDoStuff_SubResults.SourceObject = "Query.qrySubformSpecs"
The columns get in order some times, but not consistently.
I also want to fit the columns a small as they can, fitting the contents of their respective data, if that's possible. The column fit is not as big of a deal, because the user can select the left corner and then double-click between the columns if they really need to. The order of the columns is definitely more important here.
If anyone knows how to accomplish this, I would really love the help. Thanks!
FWIW, the backend is SQL, so this is all coming from 1 big linked table. The performance is quick and not an issue, but the column order is important and needing to work right.

How can I combine these two SQL queries (Access/VBA)

I am using two SQL queries in VBA that i believe they could be done in one, but I cant get it to work. I Want to turn the VBA portion into a Query outside of VBA, the VBA keeps breaking my file due to the amount of data it processes. (By break i mean it gives a message that says "this file is not a valid database" rendering the file corrupted). I search for that error but all i found was not related to breaking because of VBA code.
Anyways, here are the two queries ran with VBA.
SELECT ET.VerintEID AS EID, Sum(ET.ExceptMin)/60 AS Exeptions
FROM Tbl_VExceptTime AS ET
INNER JOIN Tbl_VCodes ON ET.Exception = Tbl_VCodes.Exception
WHERE (ET.ExceptDate Between #" & sDate & "# And #" & eDate & "#)
GROUP BY ET.VerintEID, Tbl_VCodes.IsApd
HAVING Tbl_VCodes.IsApd = ""OFF"";
I loop these results to update a table.
Do While Not .EOF
SQL = "UPDATE Tbl_AttendanceByAgent SET EXC = " & recSet.Fields(1).Value & _
" WHERE VerintID = '" & recSet.Fields(0).Value & "'"
CurrentDb.Execute SQL
.MoveNext
Loop
I know that i can save the results from the first query into a table and without looping I can update the main table with another SQL query, but I believe it can be done on a single SQL. I have tried using an UPDATE with a SELECT of the first query but it just errors out on me with an invalid syntax.
Yes this could be achieved in one single query as shown below
UPDATE Tbl_AttendanceByAgent
SET Tbl_AttendanceByAgent.EXC = t2.Exeptions
from Tbl_AttendanceByAgent t1
inner join (
SELECT ET.VerintEID AS EID, Sum(ET.ExceptMin)/60 AS Exeptions
FROM Tbl_VExceptTime AS ET
INNER JOIN Tbl_VCodes as TV ON ET.Exception = TV.Exception
WHERE (ET.ExceptDate Between #" & sDate & "# And #" & eDate & "#)
GROUP BY ET.VerintEID, TV.IsApd
HAVING Tbl_VCodes.IsApd = 'OFF'
) AS t2 on t2.EID = t1.VerintID
Note: I suppose you will replace sDate, eDate with values within your code
This question is an answer to the described errors and the given code, although it technically does not answer the request for a single SQL statement. I started adding a comment, but that's just too tedious when this answer box allows everything to be expressed efficiently at once.
First of all, referring to CurrentDb is actually NOT a basic reference to a single object instance. Rather it is more like a function call that generates a new, unique "clone" of the underlying database object. Calling it over and over again is known to produce memory leaks, and at the least is very inefficient. See MS docs for details.
Although the given code is short, it's not sweet. Not only is it repeatedly creating new database objects, it is repeatedly executing an SQL statement to update what I assume is a single row each time. That also entails regenerating the SQL string each time.
Even if executing the SQL statement repeatedly was an efficient option, there are better ways to do that, like creating a temporary (in-memory) QueryDef object with parameters. Each loop iteration then just resets the parameters and executes the same prepared SQL statement.
But in this case, it may actually be more efficient to load the table being updated into a DAO.Recordset, then use the in-memory Recordset to search for a match, then use the recordset to update the row.
I suspect that addressing a couple of those issues would make your VBA code viable.
Dim db as Database
Set db = CurrentDb 'Get just a single instance and reuse
Dim qry as QueryDef
SQL = "PARAMETERS pEXC Text ( 255 ), pID Long; " & _
" UPDATE Tbl_AttendanceByAgent SET EXC = pEXC " & _
" WHERE VerintID = pID"
set qry = db.CreateQueryDef("", SQL)
'With recSet '???
Do While Not .EOF
qry.Parameters("pEXC") = recSet.Fields(1).Value
qry.Parameters("pID") = recSet.Fields(0).Value
qry.Execute
.MoveNext
Loop
'End With recSet '???
'OR an alternative
Dim recUpdate As DAO.Recordset2
Set recUpdate = db.OpenRecordset("Tbl_AttendanceByAgent", DB_OPEN_TABLE)
Do While Not .EOF
recUpdate.FindFirst "VerintID = " & recSet.Fields(0).Value
If Not recUpdate.NoMatch Then
recUpdate.Edit
recUpdate.Fields("EXC") = recSet.Fields(1).Value
recUpdate.Update
End If
.MoveNext
Loop
I realized in commenting on Gro's answer, that the original query's aggregate clauses will produce unique values on EID, but it then becomes obvious that there is no need to group on (and sum) values which do not have Tbl_VCodes.IsApd = 'OFF'. The query would be more efficient like
SELECT ET.VerintEID AS EID, Sum(ET.ExceptMin)/60 AS Exeptions
FROM Tbl_VExceptTime AS ET
INNER JOIN Tbl_VCodes ON ET.Exception = Tbl_VCodes.Exception
WHERE (ET.ExceptDate Between #" & sDate & "# And #" & eDate & "#)
AND Tbl_VCodes.IsApd = 'OFF'
GROUP BY ET.VerintEID;
BTW, you could consider implementing the same temporary QueryDef pattern as I showed above, then you'd change the first WHERE expression to something like
PARAMETERS PsDate DateTime, PeDate DateTime;
...
WHERE (ET.ExceptDate Between [PsDate] And [PeDate])
...

Access 2007 VBA: Returning data from SQL statements that use multiple variables

I am working on a form that is meant to analyze financial data ahead of an insurance policy renewal. It needs to pull various premium and claim $$ totals from the tables, and insert them into the form. From there, it will run some calculations with them, but that should be the easy part. Where I'm struggling is the SQL statements to get the data, in the first place.
After narrowing it down a bit, I've found that the problem is the code is putting the SQL statement into the field on the form, instead of the answer the SQL statement should be providing. I have tried multiple things I've seen online, and can't figure out how to resolve this.
One of the SQL statements reads like this:
L12W = "SELECT Sum(tblActPrem.APWrit) AS SumOfAPWrit FROM tblActPrem " _
& " WHERE tblActPrem.EntID = '" & Me.ctlActEntID & "' " _
& " AND tblActPrem.PolNum = '" & Me.ctltblRnwlTrack_PolNum & "'" _
& " AND tblActPrem.APDate BETWEEN #" & L12M & "# AND #" & Me.ctlRnwAnalysisDt & "#;"""
It should be totalling premium data from the table, where the policy number and account number match what's on the form, and between the selected dates, and putting that total into the field on the form. Instead, I get this on the form:
SELECT Sum(tblActPrem.APWrit) AS SumOfAPWrit FROM tblActPrem WHERE tblActPrem.EntID = '1235' AND tblActPrem.PolNum = 'Policy1' AND tblActPrem.APDate BETWEEN #1/1/2014# AND #1/1/2015#;"
That is exactly how the statement should be running, but can anyone tell me how to make the leap from the statement, to the data?
Thank you!
Consider using DLookup or DSum in the control source of the form's field.
DLookup Solution
First, change your VBA SQL query into a stored SQL Query (notice quotes and # symbols are not necessary when referencing form controls):
SELECT Sum(tblActPrem.APWrit) AS SumOfAPWrit
FROM tblActPrem
WHERE tblActPrem.EntID = Forms!<yourformname>!ctlActEntID
AND tblActPrem.PolNum = Forms!<yourformname>!ctltblRnwlTrack_PolNum
AND tblActPrem.APDate BETWEEN Forms!<yourformname>!L12M
AND Forms!<yourformname>!ctlRnwAnalysisDt
And then in the form field textbox's control source use the DLookUp function (no criteria argument is needed since this should return only one value).
= DLookUp("SumOfAPWrit", "<yournewqueryname>")
DSum Solution
Alternatively, you can change the entire SQL statement into a DSum but notice how long the criteria (WHERE statement) would have to be.
= DSum("APWrit", "tblActPrem", "EntID = Forms!<yourformname>!ctlActEntID
AND PolNum = Forms!<yourformname>!ctltblRnwlTrack_PolNum
AND APDate BETWEEN Forms!<yourformname>!L12M AND Forms!<yourformname>!ctlRnwAnalysisDt")

Join query VB.net datareader

My query on two different tables user table and zone table is creating a problem:
cmd.CommandText = "SELECT zone_name, zone_difference FROM user_master INNER JOIN zones on user_master.zone_id = zones.ID WHERE user_master.uname LIKE " & """" & usr_gl & """"
Dim reader_q As OleDbDataReader
reader_q = cmd.ExecuteReader()
Here, zone name and difference are from zones table and zone_id (from customer) and ID (zones) are in relation, Also user name (uname) is coming from outside as usr_gl variable for e.g. "admin"
It is saying No value given for one or two parameters. I checked all the table columns and data. The same query is running independently from Access database.
Is there anything wrong i am executing here?
Yes, you are trying to concatenate strings and this is a NO-NO in code
cmd.CommandText = "SELECT zone_name, zone_difference FROM " & _
"user_master INNER JOIN zones on user_master.zone_id = zones.ID " & _
"WHERE user_master.uname LIKE ?"
cmd.Parameters.AddWithValue("#p1", usr_gl)
Dim reader_q As OleDbDataReader
reader_q = cmd.ExecuteReader()
String concatenation is considered a bad practice because many problems could arise with that
Correct string formatting (with quotes, decimals, dates) is the first problem but the Sql Injection is the worst of all. Using Parametrized queries should avoid all of those problems

Dynamic column selection the EF4 way

I have a function that I'm trying to change from old SQL way to EF4. I know the old SQL way isn't great, but I couldn't think of a better way of doing it. Now I can't seem to figure out how to make it work in EF...
My function passes in 3 values Pos, MethID and PriceBreak. First basically I select a row then I need to select a column. but this column can change...
Original SQL:
cmd.CommandText = "SELECT " & PriceBreak & _
" AS SelectedBreak FROM PrintCost WHERE MethodID = " & MethID & _
" AND Position = " & Pos & " ;"
New EF way so far!
Using db As New quotingSystemDevEntities
Dim PriceBrakeCost = (From Breaks In db.PrintCosts
Where Breaks.MethodID = MethID And Breaks.Position = pos
Select Breaks.XXXX).SingleOrDefault
Return PriceBrakeCost
End Using
I my old SQL stuff the XXXX bit changes, whats selected. How is this possible in EF? Or perhaps there is a better way to do this?
Hope this makes sense! Thanks for your help.