Hey there,
The no column in the webform_submitted_data table is currently of the type varchar. This means that ordering by that column (which actually happens when loading a submission) doesn't work.
For example, if you have a select list with more than 10 options and you select them all, the order in which they come back from the table is 1, 10, 11, 12, 2, 3, 4, etc.
| Comment | File | Size | Author |
|---|---|---|---|
| #35 | webform-select_list_order-2449383-35.patch | 2.9 KB | quicksketch |
| #34 | webform-select_list_value_order-2449383-33.patch | 1.51 KB | danchadwick |
| #29 | 2449383-29.patch | 2.11 KB | upchuk |
| #26 | qGwS1hK.png | 33.69 KB | quicksketch |
| #1 | 2449383-1.patch | 592 bytes | upchuk |
Comments
Comment #1
upchuk commentedProposed patch changes the column type to an unsigned small int. Are there cases in which the delta is not a number? If yes, than this patch is no good and proper sorting should be done after the query.
Comment #3
upchuk commentedHm..not sure what to make of this. Locally I get a bunch of test fails even without the patch :) Even more than here..
Comment #4
danchadwick commentedThe keys are strings and often contain string values. Unlike core, all data is stored in the same table. There is no guarantee that views will order them in their no order.
Comment #5
upchuk commented@DanChadwick,
I am not talking about the keys of the select. I am talking about the delta that is stored in the table under the "no" column of the `webform_submitted_data` table. Having created a select list component with the following options:
A|A
B|B
C|C
...etc
Selecting them all would and saving the webform would save in the `no` table a numeric delta (1, 2, 3, 4). And when the webform submission is viewed, the results are ordered by that `no` column by default and you end up with a wrong order as 9 is considered bigger than 10 in varchar terms.
Maybe a bit more consideration to the issue wouldn't hurt before slamming the issue closed, as the problem is quite real...and I doubt it is designed to work like this. If a certain order is created in the select list, the same order is expected on output no?
Comment #6
danchadwick commentedSo am I. Create a grid, store the results, and look at the table. You'll see what I mean.
Comment #7
upchuk commented@DanChadwick,
Alright, that's good. This is why I asked the question:
But the solution to the problem is not "works as expected". Because when the deltas are numeric and more than 10, the ordering doesn't work anymore. So a sorting needs to be done inside
webform_get_submissionsif the deltas are numeric:Somewhere in there. I wouldn't mind proposing a patch either.
Comment #8
danchadwick commentedFollowup: You can write a views handler that casts this no column to a number, but ensure that it only runs on your select items as I suspect it will throw a SQL exception if given a alphabetic string.
Comment #9
upchuk commentedI am not talking about views. I am talking about the default page callback that displays a given webform submission...Are you on IRC?
Comment #10
danchadwick commentedI don't use IRC for webform as it's best to keep the communication public in the queue for future maintainers (who might be me) to see.
The only solution then would be to modify the select component to encode the 'no' sequence "number" as a variable key. I'm not sure what issues this might cause for other modules. For example:
0
1
...
9
A10
A11
...
A99
B100
B101
...
B999
C1000
OR
10
11
...
19
210
211
...
299
3100
3101
...
3999
41000
The former is shorter and is the same for the typical case of <=9 values. The latter case is numeric, which means that any code relying on the 'no' field will still work if PHP type-coerces the string to a number.
You'd also have to look at any other components that store multiple values to see if they are affected.
Comment #11
upchuk commentedPerhaps. I will look into this. But can't we deal with it on output though? After the query is made I mean Casting the `no` values to integer if they are numeric. Because technically, the data in the column is not wrong. It's just interpreted wrong by default.
Comment #12
danchadwick commentedOther data in 'no' isn't numeric. I don't see how that would work. And these tables can be huge, so we need to consider any performance consequences.
Comment #13
upchuk commentedWell, inside of
webform_get_submissions, instead of :we can try:
Running each component through ksort(). Do you think this would have too much of a performance impact? This would sort both string and numeric values (although for the string values it shouldn't make a difference).
I haven't really tested this yet, it's mostly theory at this point.
Comment #14
upchuk commentedAlso, this is not a feature request but a bug report because the values are not ordered as expected (0,1,2,3) but 0, 1, 10, 11, 2, 3.
Comment #15
danchadwick commentedI think what you mean is:
With lots of components and/or lots of submission, that's a ton of calls to ksort for a 3-sigma boundary condition. Maybe 1 time in 10,000,000 would that ksort be of benefit to the user. Doesn't seem like a good idea.
Also, it doesn't help views, although I have tried the reporting to see if 'no' is even sorted upon.
I don't think webform has an obligation to return multiple select data in the order of the keys. It would be nice if it did, but fundamentally, it seems like extra credit to me.
Another alternative would be switching to Entity Form.
Comment #16
upchuk commentedA yes, of course. The code makes sense. My bad.
Alternatively you can check to make sure the component is a select type which would narrow things down considerably.
As for what webform's obligation is: in my view, if the module adds some code, it should expect it to work. In this case, it should expect
->orderBy('sd.no', 'ASC');to order the results by that column in the intended way. Not "well, sometimes it works, sometimes it doesn't". Otherwise, what is the point? This is why it's a bug and not a feature request.Also, finding bugs in webform should not prompt an invitation to switch to another module. I see the stubborn resistance you have and I've lost any interest in wasting my time trying to find a solution for this. I had spoken to Nate earlier today and had mentioned to him I'd be opening this issue so he is aware. Maybe he will drive it forward.
Comment #17
danchadwick commentedSorry you're frustrated and have lost interest. I've made several suggestions, all of which were intended to be helpful. We simply differ on whether we consider it a bug. No biggie.
If you regain interest, feel free to reopen the issue. #10 is viable, I think.
Comment #18
quicksketchThanks @DanChadwick for answering so promptly. I asked @Upchuck to file this since I already knew what he was describing after he asked me if it was a problem.
I agree that this is probably a bug, although the "no" column is indeed varchar "by design", the inaccurate ordering of results if there are more than 10 items is certainly not intentional.
In @Upchuk's case, he can probably work around the problem using the very solution he described in #13:
But instead of including it directly in Webform, he could move the added
ksortcode into a module that implementshook_webform_submission_load(). So there's also a reasonable work-around, but not ideal.Here's one approach that might work (in most cases) and not require hardly any effort at all. What if we just remove the sort entirely from the "no" column? MySQL by default will return the rows in the order they were inserted into the database, which will keep the order the way we desire. For select lists that have string-keys, we actually are causing the results to be different than the original order defined in the select list already, because a string-sort of keys is not likely to be the same order as the select list in the configuration. So by sorting right now, we're likely causing more problems than we're fixing. Removing the sort could give users (usually) accurate sorting and reduce the cost of the SQL query in the first place.
If we wanted totally accurate sorting, we'd need to do something more extensive. That would probably be creating a numeric order column in the DB for example, or manually sorting certain components.
Comment #19
quicksketchHm, well maybe depending on the inserted order isn't a good idea: http://stackoverflow.com/questions/8746519/sql-what-is-the-default-order...
However, it is still the case that we're sorting on a column that may not actually match the order of the component configuration or submission order. Perhaps we could approach this differently and simply fix the presentation of select lists, which is what @Upchuck discovered as the problem in the first place:
In all cases, the order of the select list should be displayed the same as the configuration of the component, not in a SQL-based ordering. We have this problem both for numeric values 10 and higher as well as for string-keys.
Let's change the issue title to reflect what we're trying to solve at least. Changing the "no" column to an integer isn't the right solution here.
Comment #20
quicksketchI'll also add that having a component order that sorts descending is also totally valid. There'd be nothing wrong with configuring a select component as:
Assuming these were checkboxes, when displayed, they should be ordered 10 first and 1 last to match the component configuration, rather than a sort from the database.
Comment #21
upchuk commentedHey @quicksketch, thanks for chiming in!
Regarding #18, you are right, that's exactly what I did for the client site where I discovered the problem (
hook_webform_submission_load). That works perfectly for me but I'm sure other people will run into this issue and wonder what is going on :)Just to be clear, select lists with string keys are also stored with numeric deltas in the `no` column. So a select component with these options:
If both checked, gets submitted as:
I just wanted to put this out there in case there was some confusion. If you already knew about this and I misunderstood, my bad :)
As per #19, I completely agree that changing the table column type is not possible. I was not aware of the components that store strings in there.
Agree! But I believe this happens by default no? They are inserted in the order of the options in the component? And the `no` column reflects that. And again I refer back to the select list choices being stored as integer also when they have string keys :)
Regarding #20, the example you gave will get stored like this if I'm not wrong:
So that should also already work as designed (if not more than 10 options). I will look into it some more.
Comment #22
danchadwick commented#10a. Easy, efficient, helps views.
Comment #23
quicksketchNow I'm confused, @Upchuk. In #5 you said:
But things appear fine when viewing an individual submission. Select component values are already ordered as defined in the component configuration. This already is basically required because there's no way that sorting on the "no" column will really give us the correct order of keys in all cases anyway. Although you're right that for select lists, the "no" column is numeric, for a Grid component, the keys are strings and sorting on them numerically would return the wrong results.
Likewise, I tried viewing the "Analysis" listing as well for select components, it's also in the right order.
I may have gotten mixed up here, because I thought you were describing that Webform itself was displaying values in the wrong order somewhere. If it's only in the resulting list of `webform_get_submissions()` that the data is out of order, then this really may not be a serious concern. It will simply be up to your application (assuming your calling this function manually) to order the results to match the select component order before displaying them.
I also realized that even if we did have a numeric column for ordering in the first place, this still wouldn't work in all situations. Because a user can at any time change a select component into a different order after submissions have come in, the recorded order wouldn't be accurate for displaying the submission any more either.
So, long story short: There is no way (even if we added a numeric column) to reliably "sort" data as it comes out of the database. You will always have to manually *order* (not sort) it based on the component configuration, at least when it comes to select lists and grid components. If we offered a multiple-value textfield where the "no" column really was an ordered value, this would be a much larger problem.
Have I summarized everything correctly this time?
Comment #24
quicksketchAll of that said, we could also still probably remove the
ORDER BY "no"from the query entirely for performance reasons which would reduce the cost of the query and should have no negative effects. As a side-effect, it would result in desirable results in your situation, but that would be simply a coincidence of MySQL InnoDB tables.Comment #25
upchuk commentedHehe, sorry if it got confusing somewhere :)
This is actually what I found was not the case. Let me describe the scenario:
You have one webform with one select list component (with multiple selections) with the options (needs to be over 10):
User submits the webform selecting all the letter options. When as admin you navigate to
/nid/webform/webform-resultsand click on the actual submission to view it (atnode/nid/submission/sid), you see that the letters are ordered incorrectly. So no custom code whatsoever.There is actually not a problem with the way data is stored (the `no` column correctly indicates that at the time of submission, the letter order submitted matches the component configuration). The problem is the order by the `no` column which is a varchar (9 is bigger than 10) :)
This is indeed very true. There is nothing we can do for these cases save for some costly operations that are not really worth it. It would be up to the user to make sure that in that case they display data how they want.
But I think that by default, it should be possible for users who don't make modifications to the webform component to see the right order. Please let me know if this is clearer and you reach the same conclusion :)
I will try to test and see if removing that will make the order expected (as a coincidental consequence of the order in which data went in). I'm not yet sure about this.
Comment #26
quicksketchOkay, confirmed for real this time. Definitely a problem.
To reproduce:
- Add a new form with a select component.
- Select "multiple" to make them checkboxes.
- Enter in at least 10 values. You can order them ascending but I did descending just to really demonstrate the problem:
- Now view the form and select *at least 10 options*, preferably 15 or so.
- Then view the submission.
Expected:
- The results of the select list should match the order of the component.
Actual:
- The results of the select list are in no particular order at all (from the end-user standpoint). You can make the problem even worse by editing an existing submission and adding more options.
Screenshot of the submission result for a select list with the above configuration:

Comment #27
quicksketchSo based on the above, back to my modified issue title, which accurately describes the end-user facing problem.
Comment #28
upchuk commentedI'll take a stab at it and try to come up with a patch.
Comment #29
upchuk commentedHere we go. What do you guys think?
Comment #30
danchadwick commentedImplement #10A and test. It's a line-line fix that addresses the root problem (rather than fixing it later). It helps views too. As other components are created which expect the 'no' field to behave like a weight, it will continue to give the desired result. It is also invertible -- if an index contains a characters, remove it to get the original numeric index back.
Webform has no obligation to adjust submitted data to suit changes to the form made after submission. Every component has issues when this happens. It's not something that webform can or should reasonably deal with.
Comment #31
quicksketchI don't see a problem with matching the component configuration on display. It would be relatively lightweight, as it's only done on display and we already have the full component right there.
That said, fixing the "no" column to sort correctly by prefixing with letters would indeed help Views in most cases. But updating existing submissions seems like it'd be an expensive update hook. We'd also end up slightly modifying the $submission data structure with the new keys, which might end up increasing the amount of data juggling we do.
Comment #32
danchadwick commentedLet's consider laying the groundwork for future improvements. I can see that components may well expect that if they create a typical numerically-indexed array of values (as in $values[] = 'my value') that that component would expect to get an array back in the same order. I'm thinking not so much of multi-select, but of, say, extending other components to be multi, like file for example. OTOH, they could ksort to guarantee it, although doing this on every submission would be costly when a lot of submissions are loaded (e.g. analysis, export and to a lesser extent, views).
Further, we could set the stage for views to get the rows in the same order. This would allow a future views submissions data handler to retrieve raw data and display it without calling webform_load_submissions. Combined with webform machine names and component machine names, we could have much more native views integration, which increases the power of views.
The "no" column is actually overloaded. It means two things: delta/weight and sub-component. For a grid, the 'no' contains the key of the question. There is a long-standing feature request for multi-select grids (i.e. with checkboxes, rather than radio buttons). To implement this, the 'no' keys would have to be fudged -- 'question1_1' would be the first answer and so forth. This would make a crosstab in sql all but impossible.
Options:
Comment #34
danchadwick commentedMaintainer decision: ksort values before display, to fix original issue. Larger questions about schema postponed to D8. I will create an open task for D8 schema and reference this issue.
Thanks for your help, guys.
Committed to 7.x-4.x and 8.x.
Comment #35
quicksketchThanks Dan, this solution works in almost all situations. I found a problem that the "Table" display of values is still out of order. If we want to add a ksort() to the
_webform_table_select()If you're up for matching the component order, I've attached a patch that uses the loaded component order to match the output order. I think you're right that it's not really our responsibility to deal with modified components, but this solution is still pretty easy (though not trivial) and provides a very reliable output for our users. It turns out the Analysis display already sorts based on component order, so there's no need to modify that callback.
Comment #36
upchuk commentedI see the committed patch sorts by key on display. That solves I think part of the issue at hand. But is there a problem with ordering them according to the configuration in the component (#29)? So that if after submissions the order gets changed this also gets reflected in previous submissions.
Anyway, thanks for considering and committing fixes Dan!
Comment #37
danchadwick commentedNot much of a fan of #35.
I *think* the theory of operation of grouped option display is to create a nested list of options so that an overriding theme function might use it if it wants, and then flatten it back out in the default theme function. If this isn't the case, then the code should be simplified to always pass the flattened list and remove the flattening code from the theme function.
So #35 creates the flat list. It uses it to sort the values. Then it throws that away and does the work all over again for a flat list. These lists might involve callbacks which do database or other time-consuming operations. Then the default theme function throws that work away again to flatten the list so it can use it.
I would rather see another ksort stuck into _webform_table_select and be done with it. I really don't think that re-ordering existing results based upon a schema change to a component after data has been added is worth the code complexity. It might even be argued that it's not a bonus as it doesn't represent what is actually in the database. For example, we show values that are no longer options.
@quicksketch -- if you really want to do all this work, I suggest one minor improvement:
I think it's a little cleaner than putting in duplicates and removing them with array_unique.
Too many cooks fretting over whether the cookies should be round or square. quicksketch -- commit what you prefer.
Comment #39
danchadwick commentedEeeeh. Upon further reflection, I'm not comfortable leaving table as is with half the cases fixed. I added a ksort to the table output. If quicksketch goes forward with #35, just delete the ksort before applying. In this way, the -dev release is at least consistent and if this issue gets dropped, we don't forget about the table output.
Committed to 7.x-4.x and 8.x.
Changing to Feature Request for the specific additional feature of re-ordering database data to match changes in the component schema made after the data was submitted.
Comment #40
quicksketchI'm satisfied with just the ksort(). It'll work 90% of the time and is simple.