Write multiple occurences under single cell in SQL for VBA - sql

I am working on SQL for VBA.
Usually, if we have multiple occurrences of the desired condition, each of the occurrences will be written on different cells, like the code below:
"SELECT CPID " & _
"FROM LCOND_LAST " & _
"WHERE WELL ='" & sht1.Cells(i + 3, 8) & "' " & _
"ORDER CPID"
Which will gives output:
Notice that there are 2 cells to write two occurrences.
My question is, can we just write them on single cells only?
Is there any function that allows us to do so?

You can use the DISTINCT as follows:
"SELECT WELL, CPID " & _
"FROM LCOND_LAST " & _
"WHERE WELL ='" & sht1.Cells(i + 3, 8) & "' " & _
"ORDER BY PSWELLCOND_LAST.CPID"
DISTINCT is used to filter duplicate rows
Learn more about DISTINCT from here.
-- Update
You can use the CHR(10) -- newline and aggregate it as follows:
"SELECT LISTAGG(CPID, CHR(10)) WITHIN GROUP (ORDER BY CPID) " & _
"FROM LCOND_LAST " & _
"WHERE WELL ='" & sht1.Cells(i + 3, 8) & "' "

Related

DMax within Insert Into SQL statement (not working)

I've got a piece of VBA code that pulls data in from a linked table and appends some date columns based on using the DMax function to look up the most recent transaction dates based on SKU and transaction type. I'm getting the following error:
For some reason the DMax function is not seeing the data properly from the SKU field that is in the select statement.
SQLstr = "Insert Into TEMP_ONHAND Select " & _
"COMPANY, WHSE, WHSEDESC, ITEM, ITEMDESC, ESTCOSTPRICE, INVONHAND, CONSIGNINVONHAND, " & _
"QUANTITYINTRANSIT, QTY, COST, LASTINVTRANS, SUPPLIERID, SUPPLIER, " & _
"BUYER, BUYERNAME, PLANNER, PLANNERNAME, BUYFROMBP, BUYFROMBPNAME, " & _
"[COMPANY] & '-' & [WHSE] & '-' & [ITEM] AS SKU, " & _
"Left([WHSEDESC],3) AS TYPE, " & _
"#" & DMax("[TRANSDATE]", "[TEMP_HISTORY]", "[SKU]='" & [SKU] & "' AND [TRANSTYPE] = 3") & "# AS LAST_RCPT, " & _
"#1/1/1950# AS LAST_ISSUE, " & _
"#1/1/2000# AS LAST_ADJUST, " & _
"'TEST' AS TRAN_RANGE, " & _
"'TEST' AS ADJ_RANGE " & _
"From PARTS_ONHAND;"
MsgBox SQLstr
Application.CurrentDb.Execute SQLstr
If I replace the & [SKU] & in the DMax function with an actual text string of a SKU, this code works fine. I'm wondering if the syntax needs to be different somehow within the DMax function in order to reference a field from the select portion of the statement?
The & [SKU] & code is not referencing calculated SKU field of SELECT portion of constructed SQL statement. This concatenation takes place within the VBA procedure, not the SQL statement. Therefore, VBA looks for [SKU] and can't find anything. In fact, that entire DMax() expression is executed in this VBA procedure and if it did succeed it would return a single value for concatenation and every record pulled by the SELECT would have it. If you want to reference calculated SKU field as input to DMax(), then DMax() expression must be embedded in constructed SQL statement.
Embedding domain aggregate functions with dynamic arguments within SQL constructed in VBA is tricky when text fields are the criteria. Try:
"# & DMax('[TRANSDATE]', '[TEMP_HISTORY]', '[TRANSTYPE] = 3 AND [SKU]=' & Chr(39) & [SKU] & Chr(39)) & # AS LAST_RCPT, " & _
Or build a SELECT query object which includes DMax() function then call that object by the VBA procedure.
SQLstr = "Insert Into TEMP_ONHAND Select * FROM queryName"
Or don't save aggregate data, calculate it when needed.
Try this:
SQLstr = "Insert Into TEMP_ONHAND Select " & _
"COMPANY, WHSE, WHSEDESC, ITEM, ITEMDESC, ESTCOSTPRICE, INVONHAND, CONSIGNINVONHAND, " & _
"QUANTITYINTRANSIT, QTY, COST, LASTINVTRANS, SUPPLIERID, SUPPLIER, " & _
"BUYER, BUYERNAME, PLANNER, PLANNERNAME, BUYFROMBP, BUYFROMBPNAME, " & _
"[COMPANY] & '-' & [WHSE] & '-' & [ITEM] AS SKU, " & _
"Left([WHSEDESC],3) AS TYPE, " & _
"DMax(""[TRANSDATE]"", ""[TEMP_HISTORY]"", ""[SKU] = '"" & [SKU] & ""' AND [TRANSTYPE] = 3"") AS LAST_RCPT, " & _
"#1/1/1950# AS LAST_ISSUE, " & _
"#1/1/2000# AS LAST_ADJUST, " & _
"'TEST' AS TRAN_RANGE, " & _
"'TEST' AS ADJ_RANGE " & _
"From PARTS_ONHAND;"

MS-Access VBA select query with multiple criteria

I have a dropdown box in an MS Access form which is populated by the following select query:
strSQL = "SELECT [Process] " _
& "FROM [dbo_tbl_Area_Process] " _
& "WHERE Area=" & Chr(34) & Me.Area_NC_Occurred & Chr(34) & ";"
Me.Process.RowSource = strSQL
I would like to add Active = -1 as a second criteria to the query to further limit the selections.
I have tried, so far unsuccessfully to add this second criteria and am at a loss as to how to proceed. Any help from the community would be most appreciated.
I have tried the following where conditions:
& "WHERE Area=" & Chr(34) & Me.Area_NC_Occurred & Chr(34) & " and Active =-1"
This does not return any results.
& "WHERE Area=" & Chr(34) & Me.Area_NC_Occurred & Chr(34) & " and Active ="-1""
This has a compile error:
Expected:end of statement
Following on from mintys comment regarding linked SQL server tables I changed the query to the following:
strSQL = "SELECT dbo_Tbl_Area_Process.Process " _
& "FROM dbo_Tbl_Area_Process " _
& "WHERE Area=" & Chr(34) & Me.Area_NC_Occurred & Chr(34) & " AND Active=True"
Adding the table references to the SELECT and FROM lines gives me the outputs I expected.
Thanks all for your comments

SQL query assistance needed with 'NOT'

I'm working out of VB6 with SQL SERVER 2012. I found myself in a pickle. Basically i have a query that works fine and pulls the necessary data in SQL SERVER, however, I'm having a difficult time translating it to vb6 SQL code. Here's a working query in SQL SERVER...
SELECT 'TotalSum' = SUM(Units)
FROM tblDetail
WHERE MemberID = '117'
AND CAST(SStartD AS DATETIME) >= '4/1/2016'
AND CAST(SStartD AS DATETIME) <= '4/7/2016'
AND Service = 166
AND [CODE] IN('1919')
AND NOT(InvoiceNo = '11880'
AND DtlNo = 2
)
AND NOT(InvoiceNo = '11880'
AND AdjNo = 2
);
So when I try to write it in my vb6 application i do something like
SELECT 'TotalSum' = SUM(Units)
FROM tblDetail
WHERE MemberID = '117'
AND CAST(SStartD AS DATETIME) >= '4/1/2016'
AND CAST(SStartD AS DATETIME) <= '4/7/2016'
AND Service = 166
AND [CODE] IN('1919')
AND (InvoiceNo <> '11880'
AND DtlNo <> 2
)
AND (InvoiceNo <> '11880'
AND AdjNo <> 2
);
However, this is not giving me the same results. Whats happening is in my last two clauses
( InvoiceNo <> '11880' AND DtlNo<> 2) AND (InvoiceNo <> '11880' AND AdjNo <> 2)
When I run them finally in SQL SERVER don't have paranthesis and its absolutely detrimental that the 2 seperate clauses are in paranthesis. Anyone know what I can do? I think my last resort might be to create a store procedure but i don't really want to do that.
EDIT:
g_SQL = "SELECT 'SUM' = SUM(Units) " & _
"FROM tblDetail WHERE " & _
"MemID = " & udtCDtl.Lines(udtCDtlIdx).MemID & " AND " & _
"CAST(SStartD As DateTime) >= '" & StartDate & "' AND " & _
"CAST(SStartD As DateTime) <= '" & DateAdd("d", -1, EndDate) & "' AND " & _
"Service = 166 AND " & _
"[CODE] IN (‘1919’)) And " & _
("InvoiceNo <> " & InvoiceDtlRS!InvoiceHdrNo & " OR " & _
"DtlNo <> " & (InvoiceDtlRS! InvoiceDtlNo, "")) & " AND " & _
("InvoiceNo <> " & InvoiceDtlRS!InvoiceHdrNo & " OR " & _
"AdjNo <> " & InvoiceDtlRS! InvoiceDtlNo)
Your translation of NOT(InvoiceNo = '11880' AND DtlNo = 2) to (InvoiceNo <> '11880' AND DtlNo <> 2) is incorrect.
In formal logic, !(A & B) is equivalent to (!A or !B), so it should be:
(InvoiceNo <> '11880' OR DtlNo <> 2)
This is why you're getting different results. However, why not use the original query? There's nothing in VB6 which would prevent it.
EDIT
g_SQL = "SELECT 'SUM' = SUM(Units) " & _
"FROM tblDetail WHERE " & _
"MemID = " & udtCDtl.Lines(udtCDtlIdx).MemID & " AND " & _
"CAST(SStartD As DateTime) >= '" & StartDate & "' AND " & _
"CAST(SStartD As DateTime) <= '" & DateAdd("d", -1, EndDate) & "' AND " & _
"Service = 166 AND " & _
"[CODE] IN (‘1919’)) And " & _
("InvoiceNo <> " & InvoiceDtlRS!InvoiceHdrNo & " OR " & _
"DtlNo <> " & (InvoiceDtlRS! InvoiceDtlNo, "")) & " AND " & _
("InvoiceNo <> " & InvoiceDtlRS!InvoiceHdrNo & " OR " & _
"AdjNo <> " & InvoiceDtlRS! InvoiceDtlNo)
You've got a ) in the wrong place twice. Also, the ) on the final live would be a syntax error I think. The last 5 lines should be:
"[CODE] IN (‘1919’) And " & _
("InvoiceNo <> " & InvoiceDtlRS!InvoiceHdrNo & " OR " & _
"DtlNo <> " & (InvoiceDtlRS!InvoiceDtlNo, "") & " AND " & _
("InvoiceNo <> " & InvoiceDtlRS!InvoiceHdrNo & " OR " & _
"AdjNo <> " & InvoiceDtlRS!InvoiceDtlNo & ")"
This should work. I'm able to use SQL queries using NOT with ADODB in VB6.
g_SQL = "SELECT 'SUM' = SUM(Units) " & _
"FROM tblDetail WHERE " & _
"MemID = " & udtCDtl.Lines(udtCDtlIdx).MemID & " AND " & _
"CAST(SStartD As DateTime) >= '" & StartDate & "' AND " & _
"CAST(SStartD As DateTime) <= '" & DateAdd("d", -1, EndDate) & "' AND " & _
"Service = 166 AND " & _
"[CODE] IN ('1919')) And " & _
"NOT (InvoiceNo = " & InvoiceDtlRS!InvoiceHdrNo & " AND DtlNo = " & InvoiceDtlRS!InvoiceDtlNo & ") AND " & _
"NOT (InvoiceNo = " & InvoiceDtlRS!InvoiceHdrNo & " AND AdjNo = " & InvoiceDtlRS!InvoiceDtlNo & ")"
While Marc may have given you a query that works, Simon's question is still valid. The only reason your original query wouldn't work is because you munged the quotes. You'll notice that your parentheses by the reference to InvoiceNo are outside the quotes rather than inside them (there are other problems as well, from changing your original query, but I'll leave you to figure those out for yourself). That makes them not part of the quoted string, and instead part of the VB6 expression. Frankly, Marc isn't doing you any favors by providing an alternative SQL query that happens to have all the VB6 syntax correct, while yours does not. The real problem is that you haven't worked out how to put a SQL query into a quoted string carefully enough.
You can't afford that kind of carelessness if you want to be good at what you're doing. I don't say this to be offensive, but to get your attention. By adopting Marc's solution as the correct one, you haven't really solved your problem, because your problem is a mindset that doesn't think about anything except getting something to work. That mindset makes for the worst kind of programmer, the kind that writes terrible code (hundreds of lines of code where it could be done in 10, for example) that makes nightmares for people who have to maintain it later. Don't be one of those people. When you don't know why something isn't working, go to the trouble of figuring out why. You only have to do it once for each problem, and that mindset will stand you well as you continue to develop your skills.
Again, no disrespect intended. I'm just trying to get you to understand how to avoid getting in "pickles" like this one in future. Hopefully, the next time you post a question here, the "pickle" you're in will be more sophisticated. :)
EDIT: I guess I'm not making myself clear enough. The simple rule is that you need to enclose everything in the working SQL query in quoted strings, and replace the literal search values with references to text boxes, fields, or whatever. So:
sql = "SELECT 'TotalSum' = SUM(Units) " & _
"FROM tblDetail " & _
"WHERE MemberID = '" & myVariable & "' " & _
"AND CAST(SStartD AS DATETIME) >= '" & myVariable & "' " & _
"AND CAST(SStartD AS DATETIME) <= '" & myVariable & "' " & _
"AND Service = 166 " & _
"AND [CODE] IN('1919') " & _
"AND NOT(InvoiceNo = '" & myVariable & "' " & _
"AND DtlNo = " & myVariable & _
")" & _
"AND NOT(InvoiceNo = '" & myVariable & "' " & _
"AND AdjNo = " & myVariable & _
");"
Where myVariable is whatever variable reference you want to replace your literal string with. Any examples you've given have errors in placement of double quotes, which is why you aren't getting the result you want, which is presumably a replication of your working SQL query. The reason Marc's works is not because he altered your original query (it doesn't look like he has, except to put it on less lines) but because he placed his quotation marks correctly. The reason your and simon's solutions don't work is because neither of you have. Going back to your original post, the reason that the parentheses fail to show is because you haven't enclosed them in quotes. Marc has.

Why is this access query taking so long?

I wrote an access client to do comparisons against two excel files. It loads the two excel files that are being compared into temporary tables and evaluates them based on the two queries show below.
There are two queries because sometimes one of the excel files will only have one name column. Basically the user inputs the name of the columns being compared and we change the query based on that.
The first query, cQueryFull, works perfectly and very fast (over 100k records in just a few seconds). The second query, cQueryPart, works as intended (in terms of comparison) but has never completed on tables with more than 5,000ish records. It ends up hanging for hours and I am forced to close the program.
I don't understand why one query is so much faster than the other and I was hoping someone might be able to help me figure it out and possibly fix the second query. The part of my access client that is creating the query is below:
If chkOneColumn.Value = 0 Then
' Construct Comparison Query
qString = "SELECT OriginalFile." & txtOriginalFirst.Value & " as OriginalFirstName, OriginalFile." & txtOriginalMiddle.Value & " as OriginalMiddleName, OriginalFile." & txtOriginalLast.Value & " as OriginalLastName, WorkingFile." & txtWorkingFirst.Value & " as WorkingFirstName, WorkingFile." & txtWorkingMiddle.Value & " as WorkingMiddleName, WorkingFile." & txtWorkingLast.Value & " as WorkingLastName " _
+ "FROM OriginalFile, WorkingFile " _
+ "WHERE (OriginalFile." & txtOriginalFirst.Value & " not like WorkingFile." & txtWorkingFirst.Value & " or OriginalFile." & txtOriginalMiddle.Value & " not like WorkingFile." & txtWorkingMiddle.Value & " or OriginalFile." & txtOriginalLast.Value & " not like WorkingFile." & txtWorkingLast.Value & ") " _
+ "and OriginalFile." & txtOriginalAddress.Value & " = WorkingFile." & txtWorkingAddress.Value & " " _
+ "and OriginalFile." & txtOriginalDOB.Value & " = WorkingFile." & txtWorkingDOB.Value & " "
' Open the record set
Set db = CurrentDb
Set qd = db.CreateQueryDef("cQueryFull")
With qd
.ReturnsRecords = True
.sql = qString
End With
DoCmd.OpenQuery "cQueryFull"
ElseIf chkOneColumn.Value = -1 Then
' Construct Comparison Query
qString = "SELECT OriginalFile." & txtOriginalFirst.Value & " as OriginalName, IIF(WorkingFile." & txtWorkingFirst.Value & " is null, '', WorkingFile." & txtWorkingFirst.Value & ") + IIF(WorkingFile." & txtWorkingMiddle.Value & " is null, '', ' '+WorkingFile." & txtWorkingMiddle.Value & ") + IIF(WorkingFile." & txtWorkingLast.Value & " is null, '', ' '+WorkingFile." & txtWorkingLast.Value & ") as WorkingName " _
+ "FROM OriginalFile, WorkingFile " _
+ "WHERE (OriginalFile." & txtOriginalFirst.Value & " not like '*'+WorkingFile." & txtWorkingFirst.Value & "+'*' or OriginalFile." & txtOriginalFirst.Value & " not like '*'+WorkingFile." & txtWorkingMiddle.Value & "+'*' or OriginalFile." & txtOriginalFirst.Value & " not like '*'+WorkingFile." & txtWorkingMiddle.Value & "+'*') " _
+ "and OriginalFile." & txtOriginalAddress.Value & " like WorkingFile." & txtWorkingAddress.Value + " " _
+ "and OriginalFile." & txtOriginalDOB.Value & " like WorkingFile." & txtWorkingDOB.Value & " " _
' Open the record set
Set db = CurrentDb
Set qd = db.CreateQueryDef("cQueryPart")
With qd
.ReturnsRecords = True
.sql = qString
End With
DoCmd.OpenQuery "cQueryPart"
End If
Can anyone identify the problem with my query? In case it matters, I have already tried indexing the tables before the query is built and executed. Any help would be greatly appreciated!
It's hard to tell, but I suspect the problem is with the cross joins and the amount of predicates (and type of predicates) in the WHERE clause(s).
Joining two tables like you're doing tends to create a very large set that the WHERE clause will then have to run through. Furthermore, the LIKE operator in a JET/ACE query is probably the slowest comparison operator that there is. Especially LIKE with a leading wildcard (*).
Sometimes there's just no getting around it, but sometimes it's actually faster to load pre-queried portions into (yet another) temp table and run further queries against that data.
Is there any way you can simplify your WHERE clause, or identify the predicates in distinct batches in such a way that you can run a more straighforward query first, then further process those results? (I suggest possibly writing to temp tables and further querying because subqueries are optimized and don't necessarily guarantee that the "sql logic" you write it as will be how it's actually run).

How to code multiple datasets in VB.NET?

I have a report where I need the same data, but for four separate date ranges. Currently this data is based on one month, so it's just one dataset. But now I am trying to do this with four separate datasets, where each one is filtered on each of the four date ranges. I setup my WHILE loop to loop thru all four dates. But I'm having trouble now with distinct naming these datasets. Is this the best way to do this? It looks like if I used multiple datatables for one dataset, I'd have to define each datatable column. Here is my current dataset commandstring:
commandstring = "SELECT Batch_Records.Part_Number, Batch_Records.Lot_Number, Batch_Records.Date_Received, " & _
"IsNull([Date_Completed], [Review_Date]) AS CompleteDate, Batch_Records.Error, " & _
"Batch_Records.[Group], Batch_Records.MFG, Batch_Records.MFG2, Batch_Records.QC, Batch_Records.QC2, " & _
"QC_CODES.CODE_DESC " & _
"FROM EXCEL.Batch_Records LEFT JOIN EXCEL.QC_CODES ON Batch_Records.Part_Number = QC_CODES.CODE_ID " & _
"WHERE (Batch_Records.[Group]" & TheGroup & " AND Batch_Records.Date_Received > '" & arrWeekYear(i, j).ToString("d") & "' AND Batch_Records.Date_Received < '" & arrWeekYear(i + 7, j).ToString("d") & "')"
If I understand it correctly, you want 4 ranges in one query:
extend the WHERE (and watch out for the brackets...)
"WHERE (Batch_Records.[Group]" & TheGroup &
" AND (Batch_Records.Date_Received > '" & arrWeekYear(i1, j).ToString("d") & "' AND Batch_Records.Date_Received < '" & arrWeekYear(i1 + 7, j).ToString("d") &
") or (Batch_Records.Date_Received > '" & arrWeekYear(i2, j).ToString("d") & "' AND Batch_Records.Date_Received < '" & arrWeekYear(i2 + 7, j).ToString("d") &
") or (Batch_Records.Date_Received > '" & arrWeekYear(i3, j).ToString("d") & "' AND Batch_Records.Date_Received < '" & arrWeekYear(i3 + 7, j).ToString("d") &
") or (Batch_Records.Date_Received > '" & arrWeekYear(i4, j).ToString("d") & "' AND Batch_Records.Date_Received < '" & arrWeekYear(i4 + 7, j).ToString("d") &
"'))"
Or if you want to have 4 sets of output, create a parameterized query. Run it 4 times just updating the parameter values. Thus you have no naming problems as you have only 1 query.