First, my apologies if the title of this post is overly cryptic. I have a data set identifying events (academic courses) including start and end times. I want to verify that the times entered fit into a prescribed set of start and end times (slots), and spit out a report flagging courses that do not fit the prescribed slots. I also need to exclude courses with Section and/or Location codes that don't need to be checked.
I have the following tables:
Output: Course, Sec, Start, End, Location
Slots: Slot, SlotStart, SlotEnd, Term
Roomless (location codes): ID, OffcLoc
RoomlessSections: id, Section
My process is:
1. exclude Output.Sec = RoomlessSections.Section
2. exclude Output.Location = Roomless.OffcLoc
3. identify Slots.Slot where Output.Start = Slots.SlotStart
4. identify Slots.Slot where Output.End = Slots.SlotEnd
5. produce a report with the following: a. Start not found in Slots
b. End not found in Slots
c. Start and End not in matching Slot Further complicating things, the Slot Start and End times are not unique values (For example: Slot 6 is 11:30-12:20 and Slot 9 is 11:30-12:45), so I have to compare a list of possible slots based on each of Start and End to see if there is a match.
My approach has been to first try to produce the results in separate queries, thus:
Possible Start Slots: - SELECT Output.ID, Slots.Slot AS PossibleStartSlot
-
FROM [Output] LEFT JOIN Slots ON (Output.Start=Slots.SlotStart) AND (Output.Term=Slots.TermUnique);
and Possible End Slots: - SELECT Output.ID, Slots.Slot AS PossibleEndSlot
-
FROM [Output] LEFT JOIN Slots ON (Output.End = Slots.SlotEnd) AND (Output.Term = Slots.TermUnique);
Then compare the two: - SELECT Output.ID, qryPossibleStartSlots.PossibleStartSlot, qryPossibleEndSlots.PossibleEndSlot
-
FROM [Output] INNER JOIN (qryPossibleStartSlots INNER JOIN qryPossibleEndSlots ON (qryPossibleStartSlots.PossibleStartSlot = qryPossibleEndSlots.PossibleEndSlot) AND (qryPossibleStartSlots.ID = qryPossibleEndSlots.ID)) ON Output.ID = qryPossibleStartSlots.ID;
Finally, I use a fourth Query to analyze the data: - SELECT Output.Department AS Department, Output.Course AS Course, Output.Sec AS Sec, Output.Title AS Title, Output.Start1 AS Start1, Output.End1 AS End1, Output.Start AS Start, Output.End AS [End], IIf([Output].[ID] In (select ID from qryMatchedStartEndSlots),"",IIf(IsNull([Output].[Start]),"No Start Time","Start Time Mismatch")) AS StartCheck, IIf(IsNull(Output.End),"No End Time","End Time Mismatch") AS EndCheck INTO SlotCheck
-
FROM ([Output] LEFT JOIN RoomlessSections ON Output.Sec=RoomlessSections.Section) LEFT JOIN Roomless ON Output.Location=Roomless.OffcLoc
-
WHERE (([Output].[Location] Not In (Select OffcLoc from Roomless)) AND ([Output].[Sec] Not In (Select Section from RoomlessSections)));
I'm using a make table so that I can run the report separate from the query, as (I realize) running four queries like this is extremely inefficient and slow.
I know I'm going about this the hard way, but I don't know how else to build this kind of comparison.
Extra Info :
My Slots table looks like this: - Slot SlotStart SlotEnd Term
-
1 8:30 AM 9:20 AM FW
-
2 9:30 AM 10:20 AM FW
-
3 10:30 AM 11:20 AM FW
-
4 8:30 AM 9:45 AM FW
-
5 10:00 AM 11:15 AM FW
-
6 11:30 AM 12:20 PM FW
-
7 12:30 PM 1:20 PM FW
-
8 1:30 PM 2:20 PM FW
-
9 11:30 AM 12:45 PM FW
-
10 1:00 PM 2:15 PM FW
- 11 2:30 PM 3:45 PM FW
-
12 4:00 PM 5:15 PM FW
- 13 2:30 PM 3:45 PM FW
-
14 4:00 PM 5:15 PM FW
- 15 2:30 PM 5:15 PM FW
Notice how a number of start and end times repeat, and not necessarily in the same pairings. ie: 2:30 pm SlotStart shows up three times, with two different End times.
So, if I have a course with a 2:30 start, I need to be able to accept 3:45 pm or 5:15 pm as valid End times. This is why I'm trying to identify along the lines of 'if a 2:30 start could possibly be slots 11, 13 or 15, does my end time match the end times for these slots.'
So far, my efforts don't seem to be working. I think my problem is in my JOINs, but I'm not familiar enough with this kind of query to understand why.
I decided to run with the VBA idea, and built my SQL into some VBA, using make tables instead of queries. This sped things up considerably.
Here's what I came up with: - Private Sub SlotChecker()
-
On Error GoTo Err_SlotChecker
-
-
Dim strSQL As String
-
Dim fileName As String
-
-
DoCmd.SetWarnings False
-
-
If Me!fileName = "" Then
-
MsgBox "file name is blank"
-
Call RunQryCurrVerAnalysis_Click
-
End If
-
-
' make a new Output Table with Rooms (tOWR)
-
strSQL = "SELECT tO.* INTO tOWR " & _
-
"FROM [Output] AS [tO] " & _
-
"WHERE (tO.Sec Not In(SELECT [Section] " & _
-
"FROM [RoomlessSections])) " & _
-
"AND (tO.Location Not In(SELECT [OffcLoc] " & _
-
"FROM [Roomless]));"
-
DoCmd.RunSQL strSQL
-
-
' make a new Matched Sections Table
-
strSQL = "SELECT tOWR.*, tOWR.ID AS MatchedID, tSS.Slot, tSE.Slot INTO tMatched " & _
-
"FROM (tOWR LEFT JOIN Slots AS tSS ON (tOWR.Start=tSS.SlotStart) AND " & _
-
"(tOWR.Term=tSS.TermUnique)) LEFT JOIN Slots AS tSE ON (tOWR.End=tSE.SlotEnd) AND " & _
-
"(tOWR.Term=tSE.TermUnique) " & _
-
"WHERE (tOWR.Start Is Not Null) AND (tOWR.End Is Not Null) AND (tSS.SlotStart Is Not Null) " & _
-
"And (tSE.SlotEnd Is Not Null) And (tSS.Slot=tSE.Slot);"
-
-
DoCmd.RunSQL strSQL
-
-
' build and run slot check query
-
strSQL = "SELECT tOWR.*, IIF([Start] Not In (SELECT [SlotStart] FROM [Slots]), " & _
-
"IIF([End] Not In (SELECT [SlotEnd] FROM [Slots]), " & _
-
"'Start and End Times out of slot', 'Start Time out of slot'), " & _
-
"IIF([End] Not In (SELECT [SlotEnd] FROM [Slots]), " & _
-
"'End Time out of slot', " & _
-
"IIF([tOWR].[ID] In (SELECT [MatchedID] FROM [tMatched]),'normal', 'cross-slot section'))) AS SlotCheck " & _
-
"INTO tSlotCheck " & _
-
"FROM tOWR; "
-
-
DoCmd.RunSQL strSQL
-
-
' Call up the report
-
stDocName = "Slot Check"
-
DoCmd.OpenReport stDocName, acPreview
-
-
-
Exit_SlotChecker:
-
DoCmd.SetWarnings True
-
DoCmd.Hourglass False
-
Exit Sub
-
-
Err_SlotChecker:
-
DoCmd.Hourglass False
-
MsgBox Err.Description
-
Resume Exit_SlotChecker
-
End Sub
-
27 1893
This can probably be attempted in Code, if you like I'll give it a shot when I hqqve some time.
I'd love the help. If you can even suggest the type of method you might use I can start looking. I'm just so new to VBA I don't know where to start.
In general, the following Code will: - Accept Input from the User for the Start and End Times. This is accomplished via 2 Text Boxes (txtStartTime and txtEndTime) on a Form.
- Check the Start Time entered with existing Values in the Slots Table.
- If the Start Time does not exist in Slots, notify the User then Exit.
- If the Start Time exists in Slots, check the entered End Time against End Times in Slots for the given Start Time.
- If the End Time does not exist (Start Time does), notify User and Exit.
- If both the Start and End Times are Valid Entries, post the available Slots (1 to 15) in a List Box (lstSlots) on the Form.
- Realizing that all this may be totally confusing to you, in addition to the posted Code, I've also Attached a Demo that I created for you.
- Study the Demo carefully, and should you have any questions, feel free to ask.
-
Dim strSQL As String
-
Dim MyDB As DAO.Database
-
Dim rstSlots As DAO.Recordset
-
-
Me![lstSlots].RowSource = "" 'Clear ListBox
-
-
'Need Values for both Start and End Times
-
If IsNull(Me![txtStartTime]) Or IsNull(Me![txtEndTime]) Then Exit Sub
-
-
If DCount("*", "Slots", "[SlotStart] = #" & Me![txtStartTime] & "#") = 0 Then
-
MsgBox "No available Slots for the specified Start Time of [" & Format$(Me![txtStartTime], "Medium Time") & _
-
"]", vbExclamation, "No Matching Start Time"
-
Exit Sub
-
Else 'Start Time Matches, but does the End Time?
-
If DCount("*", "Slots", "[SlotStart] = #" & Me![txtStartTime] & "# AND [SlotEnd] = #" & _
-
Me![txtEndTime] & "#") = 0 Then
-
MsgBox "No available Slots for the specified Start/End Time combination", vbExclamation, _
-
"No Matching Start/End Time Combination"
-
Exit Sub
-
Else
-
'There is at least 1 Slot available for the Start and End Times, what is it/are they?
-
strSQL = "SELECT * FROM Slots WHERE [SlotStart] = #" & Me![txtStartTime] & "# AND [SlotEnd] = #" & _
-
Me![txtEndTime] & "# ORDER BY [Slot]"
-
Set MyDB = CurrentDb
-
Set rstSlots = MyDB.OpenRecordset(strSQL, dbOpenForwardOnly)
-
Me![lstSlots].AddItem "Slot;Start;Stop;Term"
-
With rstSlots
-
Do While Not .EOF
-
Me![lstSlots].AddItem ![Slot] & ";" & ![SlotStart] & ";" & ![SlotEnd] & ";" & ![Term]
-
.MoveNext
-
Loop
-
End With
-
End If
-
End If
-
-
rstSlots.Close
-
Set rstSlots = Nothing
P.S. - I see no way how this can be accomplished via SQL, but I am not the person to ask regarding this. Hopefully, NeoPa, Rabbit, or one of the other SQL Phenoms will see this Thread and give their opinion.
Basically you want to find
a. Start not found in Slots
b. End not found in Slots
c. Start and End not in matching Slot
But do you even need c? If they're in c then they must be in either a or b. - SELECT o.*
-
FROM Output AS o
-
LEFT JOIN Slots AS s
-
ON o.[Start] = s.SlotStart
-
WHERE s.SlotStartIS NULL
-
-
UNION
-
-
SELECT o.*
-
FROM Output AS o
-
LEFT JOIN Slots AS s
-
ON o.[End] = s.SlotEnd
-
WHERE s.StartTime IS NULL
Rabbit: yes, c is where I check whether or not courses that are found in both start and end slots have a matching slot number (if they do, I want to exclude them from my report).
ADezii: I haven't had a chance to take a look at your example, but thank you for providing it!
What I'm trying to say is there's no need to check for c. Because if they fall under c, they must necessarily fall under a or b. The query should be pretty close to what you're looking for.
NeoPa 32,556
Expert Mod 16PB Rabbit:
Basically you want to find
a. Start not found in Slots
b. End not found in Slots
c. Start and End not in matching Slot
But do you even need c? If they're in c then they must be in either a or b.
I imagine that should probably read : a. [Start] but not [End] found in Slots.
b. [End] but not [Start] found in Slots.
c. Neither [Start] nor [End] found in Slots This includes all the same records, but simply separates them in the report into different batches.
If so, then your concept is the approach that I would have recommended. It has the beauty of clearing away duplicates automatically from the result set, which is inherent in the UNION clause.
What it won't do as it stands though, is indicate the status values required for the report, as only the [Output] data is included in the SELECT clause. It's certainly a very important basis from which to start though. - SELECT tS.SlotStart
-
, tS.SlotEnd
-
, tO.*
-
FROM [Output] AS [tO]
-
LEFT JOIN
-
[Slots] AS [tS]
-
ON tO.Start = tS.SlotStart
-
WHERE (tS.SlotStart IS NULL)
-
AND (tO.Sec Not In(SELECT [Section]
-
FROM [RoomlessSections]))
-
AND (tO.Location Not In(SELECT [OffcLoc]
-
FROM [Roomless]))
-
-
UNION
-
-
SELECT tS.SlotStart
-
, tS.SlotEnd
-
, tO.*
-
FROM [Output] AS [tO]
-
LEFT JOIN
-
[Slots] AS [tS]
-
ON tO.End = tS.SlotEnd
-
WHERE (tS.SlotEnd IS NULL)
-
AND (tO.Sec Not In(SELECT [Section]
-
FROM [RoomlessSections]))
-
AND (tO.Location Not In(SELECT [OffcLoc]
-
FROM [Roomless]))
Rabbit, you're right that if something falls under a. and b. it would necessarily fall under c., making c. redundant. But the c. I'm looking for is whether or not, in cases when [Start] and [End] are found in Slots, whether or not the slots (or possible slots) for each match.
Thus:
a. [Start] but not [End] found in Slots ("End time mismatch")
b. [End] but not [Start] found in Slots ("Start time mismatch") c. [Start] and [End] found in Slots, but Slots don't match
Option C example (matching slots):
[Start]= 2:30 PM
[End] = 3:45 PM
I need to figure out that [Start] can be either slot 11 or 13, and I need to compare this to [End] which can be (in this example) either slot 11 or 13. This example would indicate a 'normal' course that doesn't need to be flagged.
In some cases there will be multiple matching slots (as in the above example), in some cases only one slot option will match, and in other cases no slot option will match.
Option C example 2 (non-matching slots):
[Start] = 1:00 PM
[End] = 3:45 PM
In this case, [Start] is slot 10 and [End] could be either slot 11 or 13. Because the possible slots don't match, I want to flag this course as being outside of the normal slot system.
The code offered by NeoPa in the previous comment provides for Options a. and b. but naturally excludes c.
I think I'm going to need to run a separate query to do the slot matching. How would I identify the possible slots in order to compare them? This is a bit of a shot in the dark, but could I store the options in an array in a DO loop?
As long as it doesn't matter what the actual error classification is, you just need to add an additional union query to my original suggestion. - SELECT o.*
-
FROM Output AS o
-
LEFT JOIN Slots AS s
-
ON o.[Start] = s.SlotStart
-
WHERE s.SlotStart IS NULL
-
-
UNION
-
-
SELECT o.*
-
FROM Output AS o
-
LEFT JOIN Slots AS s
-
ON o.[End] = s.SlotEnd
-
WHERE s.StartTime IS NULL
-
-
UNION
-
-
SELECT o.*
-
FROM Output AS o
-
LEFT JOIN Slots AS s
-
ON o.[Start] = s.SlotStart AND o.[End] = s.SlotEnd
-
WHERE s.StartTime IS NULL
NeoPa 32,556
Expert Mod 16PB
I'm starting to realise this concept won't work as intended :-( I know Rabbit will correct me if I go astray, but here's my latest thinking.
It seems that the original question was mis-expressed, as point 5c (Originally a second 5a, but that's fixed as I just noticed it now.) clearly stated that records where neither [Start] nor [End] were required, whereas post #6 indicates categorically they now are not. Not that this was the reason for the earlier SQL being wrong at all, at least not as far as I'm concerned, but it does effect the SQL we're now looking for of course.
To make life simpler I'll create SQL sets that can be saved as QueryDefs in the database. This can all be done with subqueries in SQL etc (See Subqueries in SQL.) but it can lead to some very complicated (verbose) SQL with many repetitions (especially using Jet SQL as is native in Access). qryOutputNoRooms : - SELECT tO.*
-
FROM [Output] AS [tO]
-
WHERE (tO.Sec Not In(SELECT [Section]
-
FROM [RoomlessSections]))
-
AND (tO.Location Not In(SELECT [OffcLoc]
-
FROM [Roomless]))
qryOutputMatch : - SELECT qONR.Start
-
, qONR.End
-
FROM [qryOutputNoRooms] AS [qONR]
-
INNER JOIN
-
[Slots] AS [tS]
-
ON (qONR.Start = tS.SlotStart)
-
AND (qONR.End = tS.SlotEnd)
qryResults : - SELECT qONR.*
-
, tSS.SlotStart
-
, tSE.SlotEnd
-
FROM (([qryOutputNoRooms] AS [qONR]
-
LEFT JOIN
-
[qryOutputMatch] AS [qOM]
-
ON (qONR.Start = qOM.Start)
-
AND (qONR.End = qOM.End))
-
LEFT JOIN
-
[Slots] AS [tSS]
-
ON (qONR.Start = tSS.SlotStart))
-
LEFT JOIN
-
[Slots] AS [tSE]
-
ON (qONR.End = tSE.SlotEnd)
-
WHERE (qOM.Start IS NULL)
-
AND (
-
((tSS.SlotStart IS NULL) AND (tSE.SlotEnd IS NOT NULL))
-
OR ((tSS.SlotStart IS NOT NULL) AND (tSE.SlotEnd IS NULL)))
I should clarify that tSS.SlotStart and tSE.SlotEnd are there to be used in the report to indicate what type of problem has been identified. A Null in either position indicates the missing match.
You know, I think it's been overcomplicated. Isn't the actual goal to identify everything without an exact match? Isn't this all that's needed? - SELECT o.*
-
FROM Output AS o
-
LEFT JOIN Slots AS s
-
ON o.[Start] = s.SlotStart AND o.[End] = s.SlotEnd
-
WHERE s.SlotStart IS NULL
-
AND o.Sec Not In (SELECT Section FROM RoomlessSections)
-
AND o.Location Not In (SELECT OffcLoc FROM Roomless)
Yes, this doesn't identify the "error" but I don't think that was needed in the first place. All that was needed was to identify the records.
NeoPa 32,556
Expert Mod 16PB
Having just read Joel's latest explanation of point 5c in post #9 I was further confused, so I went back over post #6 to realise I'd been confused by the explanation there last time. I think I eventually understand what he was trying to say (which was closer to my original understanding of it before the explanation) and this means that the solution I provided in post #11 has three extraneous lines at the end. Essentially, lines #16 through #18 are not necessary for this scenario. The SQL finishes neatly at line #15 and if situation 5c occurs then neither tSS.SlotStart nor tSE.SlotEnd will be Null.
NeoPa 32,556
Expert Mod 16PB Rabbit:
Isn't this all that's needed?
I don't believe so. That doesn't provide information with which to indicate which of the three scenarios (5a, 5b or 5c) each record falls into. Rabbit:
but I don't think that was needed in the first place. All that was needed was to identify the records.
I'm not sure why you'd say that. Point #5 seems to specify the requirement to identify which type each failed record falls into.
I don't believe so. That doesn't provide information with which to indicate which of the three scenarios (5a, 5b or 5c) each record falls into.
I would contend that this information was not needed in the first place. I think the OP was only identifying the types of records they want to see rather than indicating that it also be part of the result set.
P.S. Nevermind, I was wrong. I took a look at the original post's fourth query and the type of error was in there.
NeoPa 32,556
Expert Mod 16PB Rabbit:
Nevermind, I was wrong.
At last!
Not that I feel any form of schadenfreude. Simply that I was starting to feel that every time we disagreed I turned out to be the one having to admit I was wrong. You still win on points of course, but at least it's no longer a whitewash :-D
I think neither of our queries work. Because of the hitherto unforeseen 5d error. Where neither start nor end is in the table. -
o.Start o.End type
-
01:00 02:00
-
03:00 04:00 a
-
05:00 06:00 b
-
01:00 06:00 c
-
05:00 04:00 d
-
-
s.Start s.End
-
01:00 02:00
-
03:00 06:00
NeoPa 32,556
Expert Mod 16PB
I believe the SQL in post #11 (excluding lines #16 through #18 as amended in post #13) handles that OK. If you're convinced otherwise I'll have to knock up a test-rig to test it out, but I thought that was handled automatically in my code.
I would have try some sample data but I don't think your solution would identify c or d errors. I believe the errors are defined as:
a. start is in one of the records in the table but end is not in any of the records.
b. end is in one of the records in the table but start is not in any of the records.
c. either start or end is in one of the records in the table but the other is not in any of the records.
d. (new) start and end does not exist is any of the records in the table.
NeoPa 32,556
Expert Mod 16PB
It appears there's still some confusion over the specification as described in point #5. Let me see if I can clarify things a little : Possible Scenarios : - A matching [Slots] record is found where Output.Start = Slots.SlotStart and Output.End = Slots.SlotEnd.
- [Slots] record(s) are found that match Output.Start = Slots.SlotStart but not Output.End = Slots.SlotEnd.
- [Slots] record(s) are found that match Output.End = Slots.SlotEnd but not Output.Start = Slots.SlotStart.
- There are [Slots] records that match Output.Start = Slots.SlotStart and Output.End = Slots.SlotEnd, but none that do both.
- Neither Output.Start nor Output.End have matching values anywhere in [Slots].
My understanding is that all records are required from [Output] except those in scenario #1.
As such, I believe your scenario d was, indeed, previously unspecified, and matches scenario #5 above. However, your scenario c describes a set consisting of scenarios #2 & #3 above, rather than scenario #4.
All that being said, I would expect my code, as it works on the simple basis of excluding scenario #1 records, to cover all the other scenarios adequately (unless I have a flaw in my logic somewhere).
The values contained in Slots.SlotStart and Slots.SlotEnd will indicate which scenario a particular record belongs to as follows : - This never occurs due to line #15 in SQL.
- Slots.SlotStart Is Not Null but Slots.SlotEnd Is Null.
- Slots.SlotStart Is Null but Slots.SlotEnd Is Not Null.
- Neither of Slots.SlotStart nor Slots.SlotEnd is Null.
- Both of Slots.SlotStart and Slots.SlotEnd are Null.
NeoPa 32,556
Expert Mod 16PB
As the last three lines of that SQL may still be muddying the waters for people, and also because, now UNION is no longer included in the mix there may be duplication of records in my previous version, I will post an amended version which includes the DISTINCT predicate to handle that likelihood (It also saves having to scroll down so far to check the details) : qryResults : - SELECT DISTINCT
-
qONR.*
-
, tSS.SlotStart
-
, tSE.SlotEnd
-
FROM (([qryOutputNoRooms] AS [qONR]
-
LEFT JOIN
-
[qryOutputMatch] AS [qOM]
-
ON (qONR.Start = qOM.Start)
-
AND (qONR.End = qOM.End))
-
LEFT JOIN
-
[Slots] AS [tSS]
-
ON (qONR.Start = tSS.SlotStart))
-
LEFT JOIN
-
[Slots] AS [tSE]
-
ON (qONR.End = tSE.SlotEnd)
-
WHERE (qOM.Start IS NULL)
[qryOutputNoRooms] and [qryOutputMatch] may still be found in their original versions in post #11.
PS. I also found a mis-reference in the original to tO.* in the SELECT line which has now been fixed in the original.
My bad, you are absolutely right. I just had to work it out on paper to see it.
NeoPa 32,556
Expert Mod 16PB
I've been trying to post since Friday, and the Bytes server keeps timing out on me, so here goes again:
To recap: I'm trying to identify
a. [Start] but not [End] found in Slots ("End is out of slot")
b. [End] but not [Start] found in Slots ("Start is out of slot")
c. [Start] and [End] are found in Slots, but Slots don't match ("cross-slot")
Which I've tried to break down into some logic:
qrySlotCheck: - SELECT qOWR.*,
-
IIF([Start] Not In (SELECT [SlotStart] FROM [Slots]),
-
IIF([End] Not In (SELECT [SlotEnd] FROM [Slots]),
-
"Start and End Time out of slot",
-
"Start Time out of slot"
-
),
-
IIF([End] Not In (SELECT [SlotEnd] FROM [Slots]),
-
"End Time out of slot",
-
IIF([qOWR].[ID] In (SELECT [MatchedID] FROM [qryMatched]),"normal", "cross-slot section")
-
)
-
) AS SlotCheck
-
FROM [qryOutputWithRooms] AS [qOWR];
qryMatched: - SELECT
-
qOWR.*, qOWR.ID AS MatchedID
-
, tSS.Slot
-
, tSE.Slot
-
FROM ([qryOutputWithRooms] AS [qOWR]
-
LEFT JOIN
-
[Slots] AS [tSS]
-
ON (qOWR.Start = tSS.SlotStart AND qOWR.Term = tSS.TermUnique))
-
LEFT JOIN
-
[Slots] AS [tSE]
-
ON (qOWR.End = tSE.SlotEnd AND qOWR.Term = tSE.TermUnique)
-
WHERE (tSS.SlotStart IS NOT NULL) AND (tSE.SlotEnd IS NOT NULL) AND (tSS.Slot = tSE.Slot);
(note that I renamed qOWR.ID here because I was getting an error in my main query due to ID showing up twice.)
and qryOutputWithRooms: - SELECT tO.*
-
FROM [Output] AS [tO]
-
WHERE (tO.Sec Not In(SELECT [Section] FROM [RoomlessSections]))
-
AND (tO.Location Not In(SELECT [OffcLoc] FROM [Roomless]));
I think this is giving me the results I need, but I have to spend some time with the results to be sure.
I do have two major concerns with this code:
1. qryOutputWithRooms produces 1607 records, while qrySlotCheck produced 1591 records. I need to compare the records to see which ones were dropped, but it gets tricky due to the second issue:
2. Running qrySlotCheck took nearly half an hour! I think I'm approaching some record for inefficient code. I'm sure this is because I'm running huge sub-queries against each record, but I'm still working on finding another way to produce the results.
I hope the logic in qrySlotCheck clears up some of the confusion about what it is I'm looking for. Specifically, I need to be able to produce explicit comments regarding which of the three issues noted above is being flagged.
I did consider trying some kind of flagging in a UNION, like - SELECT qOWR.*
- , IIF([tSS].[SlotStart] = "", "Start Time out of Slot","") AS Check
-
FROM [qryOutputWithRooms] AS [qOWR]
-
LEFT JOIN
-
[Slots] AS [tSS]
-
ON (qOWR.Start = tSS.SlotStart)
-
-
UNION
-
-
SELECT qOWR.*
- , IIF([tSE].[SlotEnd] = "", "End Time out of Slot","") AS Check
-
FROM [qryOutputWithRooms] AS [qOWR]
-
LEFT JOIN
-
[Slots] AS [tSE]
-
ON (qOWR.End = tSE.SlotEnd);
-
Even if I used this as the first half of a query that then went on to check matched slots, this doesn't allow for the specific reporting I'm looking for (particularly where both Start and End are not found).
Would it be better to run the whole thing in VBA, turn my sub-queries into make tables at the beginning of the process, and delete them when I'm done with them? I would think this would at least speed things up.
I decided to run with the VBA idea, and built my SQL into some VBA, using make tables instead of queries. This sped things up considerably.
Here's what I came up with: - Private Sub SlotChecker()
-
On Error GoTo Err_SlotChecker
-
-
Dim strSQL As String
-
Dim fileName As String
-
-
DoCmd.SetWarnings False
-
-
If Me!fileName = "" Then
-
MsgBox "file name is blank"
-
Call RunQryCurrVerAnalysis_Click
-
End If
-
-
' make a new Output Table with Rooms (tOWR)
-
strSQL = "SELECT tO.* INTO tOWR " & _
-
"FROM [Output] AS [tO] " & _
-
"WHERE (tO.Sec Not In(SELECT [Section] " & _
-
"FROM [RoomlessSections])) " & _
-
"AND (tO.Location Not In(SELECT [OffcLoc] " & _
-
"FROM [Roomless]));"
-
DoCmd.RunSQL strSQL
-
-
' make a new Matched Sections Table
-
strSQL = "SELECT tOWR.*, tOWR.ID AS MatchedID, tSS.Slot, tSE.Slot INTO tMatched " & _
-
"FROM (tOWR LEFT JOIN Slots AS tSS ON (tOWR.Start=tSS.SlotStart) AND " & _
-
"(tOWR.Term=tSS.TermUnique)) LEFT JOIN Slots AS tSE ON (tOWR.End=tSE.SlotEnd) AND " & _
-
"(tOWR.Term=tSE.TermUnique) " & _
-
"WHERE (tOWR.Start Is Not Null) AND (tOWR.End Is Not Null) AND (tSS.SlotStart Is Not Null) " & _
-
"And (tSE.SlotEnd Is Not Null) And (tSS.Slot=tSE.Slot);"
-
-
DoCmd.RunSQL strSQL
-
-
' build and run slot check query
-
strSQL = "SELECT tOWR.*, IIF([Start] Not In (SELECT [SlotStart] FROM [Slots]), " & _
-
"IIF([End] Not In (SELECT [SlotEnd] FROM [Slots]), " & _
-
"'Start and End Times out of slot', 'Start Time out of slot'), " & _
-
"IIF([End] Not In (SELECT [SlotEnd] FROM [Slots]), " & _
-
"'End Time out of slot', " & _
-
"IIF([tOWR].[ID] In (SELECT [MatchedID] FROM [tMatched]),'normal', 'cross-slot section'))) AS SlotCheck " & _
-
"INTO tSlotCheck " & _
-
"FROM tOWR; "
-
-
DoCmd.RunSQL strSQL
-
-
' Call up the report
-
stDocName = "Slot Check"
-
DoCmd.OpenReport stDocName, acPreview
-
-
-
Exit_SlotChecker:
-
DoCmd.SetWarnings True
-
DoCmd.Hourglass False
-
Exit Sub
-
-
Err_SlotChecker:
-
DoCmd.Hourglass False
-
MsgBox Err.Description
-
Resume Exit_SlotChecker
-
End Sub
-
NeoPa 32,556
Expert Mod 16PB
As a matter of interest Joel, might we know why you decided to ignore the SQL suggested and go off at a tangent?
I can see why you decided to go with VBA when your SQL failed, but why change the SQL at all in the first place? It doesn't seem a very logical approach (I'm English so I'm allowed to get away with such heavy understatement). Did you find it didn't work?
Unfortunately, I cannot help you if you take that approach. There's not even feedback to explain why it isn't used, so there's no logic path even to try to follow here. Clearly I'm interested in your response, but beyond that I can only wish you good luck with your project and console myself that the hours put into it were educational for me and, hopefully, other readers of this thread too.
I hope I gave some indication in post #24 regarding the processing time of the SQL approach (20-30 minutes for 1600 records) which led me to change approach by using make tables instead of queries. As for the change to VBA, I had two reasons. First, I needed something that would clearly delimit which criteria each record triggers, and that required at least some additional code from where we were with the SQL; second, the logic had a clear bifurcation between records with valid start/end times and those without. This required (from my understanding) splitting the logic into an if statement that could handle four different combinations - something that seemed to get overly complicated in SQL. All of the suggestions offered here gave me a much better understanding of the way to approach the problem (and helped me build the queries in my solution), so I would say your contributions were quite helpful, and not a waste at all. When it came down to it, I needed to take your suggestions on how to identify the different combinations and turn it into something that could run faster, and spit out the detailed analysis I was looking for, which seems to run much more elegantly in VBA.
Thanks for all your help! I truly do appreciate it, and would not have come to a solution without it.
NeoPa 32,556
Expert Mod 16PB Joel:
I hope I gave some indication in post #24 regarding the processing time of the SQL approach
You certainly gave an indication of the problems with the SQL you came up with. I was trying to make the point that you hadn't commented on the SQL I suggested. Clearly (not from any comments but from reading between the lines) you felt that there was information missing from the SQL suggested - which is unfortunate as it was there if you had recognised it - and decided to add chunks that would certainly be expected to reduce efficiency drastically. This is why an ongoing dialogue of clear communication is advisable when working on a forum. I cannot help you to understand any confusion you clearly had comprehending the SQL accurately, if you never express it.
Never mind. I'm sure you're happy enough with your solution, and clearly this is all at a fairly complex level anyway, so finding a perfect way of handling it all (including responses etc) was always going to be less than straightforward.
Sign in to post your reply or Sign up for a free account.
Similar topics
by: Raymond Hettinger |
last post by:
For Py2.4, I'm working on a C implementation of Sets.py with the possibility of
having a set() type as a builtin. There is a question as whether the current
design for set of sets has been useful....
|
by: Ney André de Mello Zunion |
last post by:
Hello.
Binding a temporary to a non-const reference is illegal. Everybody
should be tired of hearing that. So should I. But then I found myself
wondering about a small piece of code I was...
|
by: Joshua Beall |
last post by:
Hi All,
I've been taking a look at DB Designer 4, and looking through the
documentation (http://www.fabforce.net/dbdesigner4/doc/index.html) I am a
little unclear on some of their nomenclature:...
|
by: wxbuff |
last post by:
I have a report based on our product names that consists of two parts.
Both insert data into a temporary table.
1. A single grouped set of results based on all products
2. Multiple tables based...
|
by: kristofvdw |
last post by:
Hi,
I have to treat a given text file, but haven't got a clue which
extended ASCII set it is using.
Opening the file in Windows' Notepad or in DOS, all accented letters
and symbols are wrong....
|
by: Ed L. |
last post by:
I am trying to identify tables with significant diskspace "leakage" due to
in appropriately low max_fsm_pages settings. I can see the results of
VACUUM ANALYZE VERBOSE output counts of tuples and...
|
by: bgkhan |
last post by:
Is there any method by which we can identify which Oracle Value Set(s) is using a specific table?
To Give you an overview of the issue, I have to register and run a report. Data is not being...
|
by: JosAH |
last post by:
Greetings,
Introduction
This week I'll write a bit about generics (those funny angular brackets). I need
an example and decided to use sets and some of their operations. This weeks'
article...
|
by: Martin Kulov [MVP] |
last post by:
Hi,
I am wondering if this problem is still valid for ASP.NET 2.0.
"To maintain session state across different Web servers in the Web farm, the
application path of the Web site (for example,...
|
by: tkpmep |
last post by:
I have a list that starts with zeros, has sporadic data, and then has
good data. I define the point at which the data turns good to be the
first index with a non-zero entry that is followed by at...
|
by: Charles Arthur |
last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
|
by: BarryA |
last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
|
by: nemocccc |
last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
|
by: Sonnysonu |
last post by:
This is the data of csv file
1 2 3
1 2 3
1 2 3
1 2 3
2 3
2 3
3
the lengths should be different i have to store the data by column-wise with in the specific length.
suppose the i have to...
|
by: marktang |
last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
|
by: Oralloy |
last post by:
Hello folks,
I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>".
The problem is that using the GNU compilers,...
|
by: Hystou |
last post by:
Overview:
Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
|
by: tracyyun |
last post by:
Dear forum friends,
With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
|
by: agi2029 |
last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
| |