I'm specifically using 2013 R2 and have not tried this in other versions:
If you do a GET on a record it should bring back ONE record if it finds it. At least that's what I thought. If you then do a REPEAT on that record after the GET it will start at the Record it got and then repeat until the end of the table (using UNTIL NEXT=0).
Not really a big deal, but seems counterintuitive to what the GET should be used for which is to get ONE record.
"Why are you putting a REPEAT after a GET anyways?", you may ask. If a value is passed to a specific function I attempt to do a GET. If the value is blank it uses a SETRANGE/FINDSET to get a list of records.
What do you think?
0
Comments
if you use GET, dont use repeat until.
Absolutely! Can't imagine a case when you repeat after get. GET is to get 1 specific record by primary key, nothing else!
With the SQL Server option, this did not change. NAV just tries to utilize data sets most efficiently behind the scenes. Operations such as FINDSET, FINDFIRST, FINDLAST, ISEMPTY, that have been introduced with SQL Server in mind, are just a way to allow you to give hints to that behind-the-scene-logic.
So any of the FIND... or GET operations primarily set a position on a record. Any NEXT, FIND('>'), FIND('<') OR FIND('='), even MODIFY, DELETE, RENAME do not even depend on any previous FIND or GET, but on the field values of the record variable you perform the operation on.
But beware: not keeping relational data sets in mind will have a performance penalty.
Using GET for anything else, while it unfortunately compiles, is incorrect coding.
RIS Plus, LLC
No filters are set or used with GET.
Emphasis by italics by me.
So, all fields of the unique primary key are defined on any GET you call, whether you specified it or not. Zero or one record match.
Have you ever done e.g. a ?
Actually you needed to code this as but that's uncommon.
A consecutive NEXT will return the next record in sorting order within the filter regardless of whether you have a simple or compound key and regardless of whether you specified values for all, some or none of the primary key fields as parameters to GET, given such record exists.
Help is very good explaining what it's SUPPOSED to do, but there are a bunch of side effects that are unfortunately not documented. This is one of those cases where the compiler falls short in catching whether the developer takes care of ALL primary key fields. As you've already stated GLSetup.GET works, where we should be forced by the compiler to actually specify GLSetup.GET('') and explicitly code for the blank value. The C/AL compiler does NOT force you to specify ALL primary key field values.
Let's say we have a table called MyTable with primary key fields A and B, and we'll do a MyTable.GET(1,2). The SQL Query will be SELECT * FROM MyTable WHERE A=1 AND B=2. The WHERE clause is here the filters go, so YES there ARE definitely filters when using GET, they are just not specified by a specific C/AL FILTER keyword. Since we have a value for both primary key values, we now uniquely identify the record, and we get just one record back.
If you do MyTable.GET(1) on this same table (and only specifying one field, even though the table has a compound primary key), the query will be SELECT * FROM MyTable WHERE A=1. This SHOULD not work, but unfortunately it does, at least the last time I tested this it did, and I do have to admit this was probably a few versions ago. Since we now only have a value for one out of two primary key fields, there is a chance that you get a whole bunch of records with only the filter on field A. In this case (let's say you have records for (1,1) and (1,2) and (1,3) GET returns three records, and a REPEAT actually DOES loop through those records.
Try it, you'll see. I did this probably back in 5.0 maybe even before that. I'm not exactly sure what I did to test it, but I definitely got more than one record back, which I was very surprised to see.
RIS Plus, LLC
Does it REALLY do this - I'd be surprised. I would expect the query to be SELECT * FROM MyTable WHERE A=1 AND B=0 because my understanding is that when not all values are supplied on a GET then NAV uses default values, I.e. 0 for Integer and Decimal, '' for Code and Text, etc... So in this instance. GET(1) is exactly the same as a GET(1,0)
Also, back to the original question, it doesn't matter what record is found with a GET, doing a REPEAT..UNTIL NEXT=0 will iterate through all remaining records (from the position of the GET onwards) which match explicit filters set by SETRANGE and SETFILTER - which I think is exactly what it should do.
Therefore, if a GET returns more than one record, then the filters did not uniquely identify one record, which means that not all primary key fields were properly filtered to uniquely identify the record. I was just adding my two cents on what I've seen when not all primary key fields were properly filtered. You don't believe me, but you are making assumptions in your argument. Try it, see for yourself. If I weren't swamped with work I would do this test again and show you in a YouTube video, but I just don't have the time for it.
None of the people replying to this topic seem to understand what "uniquely identify a record" means.
RIS Plus, LLC
I just think we are looking at this from different points of view
Regarding what happens when you don't specify all primary key fields in a GET - you're right I didn't test this at the time as I was not in a position to do this. However I have tried this out now (on 4.0 SP3 Build 23305 and also 2009 R2 build 32012) and it does do what I thought it should do, i.e.
NAV Code..
SalesLine.GET(SalesLine."Document Type"::Order,'1234'); - i.e. I purposely have not specified a value for the "Line No." field
Resulting SQL Code...
SELECT * FROM "CRONUS Company$Sales Line" WITH (READUNCOMMITTED) WHERE "Document Type"=1 AND "Document No_"='1234' AND "Line No_"=0
...i.e. the NAV Client has included the "Line No_" field in the WHERE clause (with a default 0 value) even though the GET did not specify a value for the "Line No." field.
BTW - it wasn't that I didn't believe you (I know you know NAV better than most) - it was that I was astounded that the NAV client would do such a thing (as this would result in unpredictable results). Maybe there was a bug in the NAV build that you tested this on.
I agree.
This appears to be "by design", at least it is specified that way.
I think it is confusing to talk about filters when referring to the conditions in the WHERE clause of an SQL statement, even if you may look at it as a filter. In the NAV world, a filter is always something you set explicitly (through a statement or a property) and persists until you clear it explicitly.
My NAV 2009 R2 client does a SELECT * FROM MyTable WHERE A=1 AND B=0. Exactly as specified. Values for all primary key fields are provided, at most one row matches.
Yes, REPEAT does loop, but that has nothing to do with any ambiguity in a preceding GET. It does exactly the same following a GET with as many parameters as fields in the primary key.
Well, I did. And NAV fortunately behaves as specified, which it wouldn't, if it behaved as you say (unless NAV would locate the proper record from within the set retrieved from SQL Server before GET returns).
This seems to me to be an entirely unfounded perception, probably caused by your persuasion that key fields not provided for in the parameter list of a GET statement remain unspecified. You challenged us to try it several times, so now I return this challenge to you (or just believe Kishorm and me, who did). But that's still just the SQL side of it, witch, after all, is completely irrelevant to the initial question.
So, you have never fetched an Item with a GET command? did all other Items suddenly disappear? Or did GET set a filter on your Item Table? to filter on all primary key fields? None of this ever happened. Instead NAV behaves as I detailed in my first post in this thread as far as this pertains to C/AL.
I still say that neither one of you two (vaprog and kishorm) have demonstrated what "uniquely identify" means. The notion that the SQL filters are irrelevant is absurd. When you uniquely identify a record, you only get one record. There is not more than one record, so there is no looping through any more than one record, which is technically a loop of one, but it really has nowhere else to go. If you do a GET, and you can loop from that record in the same variable, there is something else going on.
My initial point to the OP was to check and make sure that they specify all primary key fields to make sure that all of them are specified. As you have demonstrated, this is no longer a problem, so therefore the problem is somewhere else.
I didn't say anyone was wrong, YOU are telling ME that I am wrong, which I am not. We're really saying the same thing mostly, except my point about uniqueness, you really don't seem to get that.
RIS Plus, LLC
Also Kishorm's second post would not make much sense if he was not convinced that GET did not retrieve exactly one, fully identified (i.e. unambiguously identified) record.
So I really don't see why you think we did not get the concept of "uniquely identify". Where do you get that idea from?
Obviously, the WHERE conditions are not irrelevant to SQL server, but they do not have any effect on what data there will be in your C/AL record variable after any GET or whatever database operation in C/AL, as long as the C/AL operations adhere to their specification. And there has not been even an explicit claim in this thread, that NAV does not do that in regard to all those things we were talking about in this thread.
I repeat: none of the C/AL database related operations depend on what data has been fetched before. They ONLY depend on the data present in the record variable at the time the operation is executed. What happens if you create a record variable in the Integer table and do IntegerRec.Number will be 1. If you now do IntegerRec.Number will now be 11. Whatever would have happened on the SQL Server end if the Integer table was a SQL table is entirely implementation dependent.
Yes exactly. But the only problem here is a problem of understanding. The question arises only from not understanding that a loop (using NEXT) is entirely independent from the preceding GET with the exception that NEXT will use the data GET retrieved into the record variable, if not altered inbetween.
The thing we differ on in my understanding is and the implication that this would affect in any way the records returned by a subsequent REPEAT ... UNTIL NEXT=0 loop. (The way I differ with the quote might even be entirely in our understanding. GET always fills in field values of exactly one row of data into the record variable it is executed on, unless no matching record was found. Whatever else C/AL does has no consequences on the logic of the C/AL program.)
The .get issues a "select * from ... where Entry No = 2701".
The .next will then fire another "select * from ..." but of course without any where clause as there are no filters set in C/AL.
You would need to add a after the .get so that the repeat until does not do something.
FD Consulting
I think that's a totally unfair statement, please re-read our posts.
You're twisting what I said/meant. I was trying to say that the WHERE clause generated in the SQL statement relating to the C/AL "GET" statement is irrelevant to the subsequent data access - i.e. the C/AL "NEXT" statement. I.e. assume the following C/AL Code...
Customer.RESET;
Customer.GET('30000');
Customer.NEXT;
In terms of what happens in SQL...
Yes the GET statement generates a SQL Statement with a WHERE clause on the "No." field which as you say uniquely identifies the record (I have never disputed this fact)
In terms if SQL you have a dataset containing 1 record, but in terms of NAV your Customer variable does not have any filters and all records are accessible via NEXT statements. I.e. the NEXT statement will move to the next Customer after 30000.
This is why I say the WHERE clause in the SQL SELECT issued when the GET is done is not relevant any more (i.e. for the NEXT statement) - as I'm sure you know already (but for the benefit of clarity) what NAV will do is generate a new SQL SELECT statement when the C/AL NEXT is performed
And my initial post was questioning what you said happens in SQL when you do a GET without specifying all primary key fields. Yes, I made an assumption - but I was actually correct in my assumption, so no harm done - I didn't spread any mis-information.
Not true. I questioned whether NAV actually did generate a SQL SELECT without specifying all primary key fields when you have a GET that doesn't contain all primary key fields. I repeat - I didn't say you were wrong, I was just questioning whether it did really do that. My subsequent tests also show that it worked in the way I expected - so I feel justified in questioning this. Also, what is it exactly that makes you think I/we don't understand uniqueness - please re-read our posts.
If you have a table where the primary key is Integer, you (I) would assume that a GET without parameters would retrieve the record where integer is 0.
You would be correct - assuming you ran your code on the classic client. If you executed the exact same code on RTC, you got an error. For it to work on both platforms, you needed to execute a GET(0).
The problem does not exist in 2013 and may even be fixed for some 2009 builds.
Senior NAV Developer
Elbek & Vejrup