I was trying to write some migration code using UNION and an ORDER BY and found it putting the ORDER BY before the second query. Queries added via SelectQueryInterface::union() should either have their order stripped or be turned into subqueries. I think the fix is to move the UNION output in __toString() so it is called before the parts processing ORDER BY and RANGEs.
| Comment | File | Size | Author |
|---|---|---|---|
| #55 | interdiff-1145076-51-55.txt | 620 bytes | daffie |
| #55 | 1145076-55.patch | 3.76 KB | daffie |
| #55 | 1145076-55-test-only.patch | 2.51 KB | daffie |
Comments
Comment #1
hass commentedI'm using table sort in http://drupalcode.org/project/linkchecker.git/blob/refs/heads/7.x-1.x:/l... and this worked when developped it, but maybe i missed something... I guess this may be a major issue for me.
Comment #2
drewish commentedHere's a test case to demonstrate the problem. Setting to needs review to demonstrate the failure.
Comment #4
Saaraneth commentedDrupal newb here and I'm getting the same problem. I have two select queries, both of which return 3 columns that I want to union, and then order by the first field. The system always puts ORDER BY before the second query, and I get a "General error: 1221 Incorrect usage of UNION and ORDER BY" exception.
Comment #5
jbrown commentedComment #6
Micha1111 commentedsame problem here
no solution for D7 ?
Comment #7
cbergmann commentedOne Sollution is to wrap the select into parentheses.
The attached patch is against Drupal 7. It wraps the "master" select and the union selects into parentheses.
Comment #8
cbergmann commentedComment #9
ionut_ottawa commentedThis didn't work for me.
Comment #10
cbergmann commented#7: core-union-order-by-1145076-7.patch queued for re-testing.
What was the problem? Was it a problem applying the patch?
Comment #11
David_Rothstein commentedWrapping the queries in parentheses fixes the fatal error, but in most cases leaving the ORDER BY as part of the individual select statements doesn't do what you want (see e.g. http://dev.mysql.com/doc/refman/5.1/en/union.html - it doesn't affect the actual order of the final result set, but rather only is useful if you need a LIMIT on the individual selects also).
I think for this issue we should support the most common case which is to order the final query (and according to some comments I've seen that's the only one officially supported by the SQL standard, although I haven't bothered to verify).
So, the attached patch goes back to @drewish's original suggestion for how to fix this, and combines it with the tests from #2. I modified the tests a bit also, because it didn't seem like they were asserting the correct expected order?
This will need to be moved to Drupal 8, but here are patches for Drupal 7 for starters to let the testbot run against them first.
Comment #12
David_Rothstein commentedPatches for Drupal 8.
Comment #13
nagiek commentedCan we include the the wrapping parentheses (mentioned in #11, for using LIMIT with two select queries) in the patch?
Comment #14
bigjim commentedI'm seeing a similar issue with LIMIT as reported originally by @drewish concerning ORDER BY statements, #11 fixes the issue for me in D7.
Comment #15
aangel commentedYes, LIMIT is failing for me, too.
Comment #16
aangel commentedBTW, the patch doesn't work for me. DBTNG still putting the order by in the wrong place (with 7.15):
Comment #17
johnnydarkko commented#7 worked for me; the patch applied the parenthesis around the queries as expected.
#11 didn't apply the parenthesis correctly and just applies an update to a test file.
But then I came across an issue when I tried to UNION another query that was already UNION'ed:
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') UNION ( SELECT ' at line 9Sorry, I don't have the same insight as @David_Rothstein but I created a new patch variant of @cbergmann's solution from #7. Still having the same issue with LIMIT--it only applies the LIMIT to the first query. This one's over my head personally, so hopefully this patch leads to the correct solution.
Comment #18
johnnydarkko commentedSorry, the patch from #17 was bad.
Rerolled the patch here.
Comment #19
hass commentedComment #20
fuerst commentedFYI: Workaround is to put the UNIONed queries into a subquery like this:
In db_select() speech:
Comment #21
hass commentedAh... This is why have not seen it yet... :-))) good to know...
Comment #22
amcgowanca commentedWe've used the patches for D7 that have been submitted on a particular client project and it has resolved the issues that we ran into with unionizing two queries from different views. Thanks for submitting these patches, it'd be great to see these patches get put into core when ready.
Comment #23
jhedstromThis would need to be rerolled against
Drupal\Core\Database\Query\Select. It would also be great to have a simple union query test so this doesn't regress.Comment #24
jhedstromComment #25
David_Rothstein commentedThe latest Drupal 8 patch (#12) already has a test, and the patch itself still applies fine to 8.0.x - however the test needs a reroll.
I guess we need some reviewers to compare the two approaches and help decide between them.
Comment #26
David_Rothstein commentedOops.
Comment #27
rpayanmreroll from #12. Please review.
Comment #28
jhedstromComment #29
Micha1111 commentedIs this ready but not committed ?
Comment #30
jhedstromI think this is RTBC. The test has been uploaded separately to illustrate the current failure. I've updated the issue summary with a beta phase evaluation.
Comment #32
jhedstromStill green. Moving to RTBC.
Comment #33
jhedstromComment #34
alexpottI tested sqlite and postgres - both pass. I wonder what happens if both queries have an order by?
Comment #35
star-szr@alexpott it sounds like you're suggesting more test coverage, is that right?
Comment #36
ann b commentedI was hoping to create a similar query to the one below:
I agree with comment #13. Drupal wrapping the select statements in parentheses as well as allowing optional order by clauses within each select statement and outside of the whole statement would be helpful. But I also understand that drupal can't support all possible sql statements. One solution is very well-documented here. I just created a sql view and made it available to the Views Module.
I'm also on Drupal 7 so I am unable to help test patch from comment #27.
Comment #37
q0rban commentedComment #38
q0rban commentedThe patch in #11 for Drupal 7 does not work in our testing of a UNIONed query with an order by. The patch in #7 does. The union being performed is on a View query, using hook_view_pre_execute().
Comment #39
somersoft commentedPerhaps the second parameter to SelectQuery::union() could be either a string, as it is currently, or an array with associative keys for 'type', and new optional ones for 'order' and 'range'? With the '(' and ')' surrounding the query string, this allows the call to fully define the union SQL independently of the rest of the query. Please note that
I do appreciate that
I have attached a patch file for Drupal 7.42. This patch also is used in hook_views_pre_execute() in the module views_extra_handlers to combine the results from two or more views. Example of use in a patched views_extra_handlers_views_pre_execute().
Comment #41
daffie commentedalexpott said in comment #34:
Lets look at the three supported databases. The manual from SQLite is pretty clear:
SQLite allows only to add
ORDER BYat the end and is applied afer allUNIONstatements.For PostgreSQL allows to add
ORDER BYto an individual select statement if it enclosed in parentheses.The manual of MySQL is stating:
So for MySQL there is no use case because it is ignoring
ORDER BYfor individual select statements.To conclude: lets not add
ORDER BYclauses to individual select statements because our three supported databases do not like it, MySQL is ignoring it and SQLite has outlawed it completely.I had to do a reroll because the SelectTest has been moved. I did not make any code changes.
Comment #43
daffie commentedThe test failures for the patch with the tests and the fix are all not related to the patch. So I will ignore them.
I made no code changes, except for the fact that the SelectTest file location has been changed.
In comment #41 have I explained why the the problem raised by alexpott is not relevant.
This issue is a bug and as such can be applaid to 8.1.x.
The complete patch looks good to me and for me it is RTBC.
It was already RTBC for user jhedstrom in comment #32.
Removed the Beta phase evaluation from the IS.
Comment #46
daffie commentedBack to RTBC.
Comment #47
alexpottGiven we've moved UNION above limit can we add test coverage for limit with a union.
Comment #48
daffie commentedAdded the requested test for a union with a order and a limit. The test is the same as the other added test with a limit added to it.
Comment #50
jhedstromThe new test looks good. One tiny nit, and then I think this is RTBC.
Line exceeds 80 characters, so needs to be shorter.
Comment #51
daffie commentedOoops
Comment #53
jhedstromSorry @daffie I should have been more clear--it's actually this standard I was referring to:
Meaning this first line should be a single sentence that is under 80 characters. Further detail can be provided after that if needed.
I couldn't find a phpcs standard for that though over in #2571965: [meta] Fix PHP coding standards in core, stage 1, so I don't know if it's enforced or not, but would be good to fix here regardless.
Comment #54
jhedstromSomething like 'Tests UNION of multiple SELECT queries together with ORDER and LIMIT'. I'm going to mark this RTBC as that could be fixed on commit (or if @daffie gets back to this first).
Comment #55
daffie commented@jhedstrom: Now I get it. Sorry, for being a bit slow. :) And thank you for your help!
Comment #59
daffie commentedComment #60
jhedstromBack to RTBC. Thanks @daffie!
Comment #61
alexpottComment #62
alexpottCommitted and pushed 6d3fd71023d38616f4fdf7ae094a46b3ee0f7635 to 8.2.x and 62598ec to 8.1.x. Thanks!
Can someone open a new issue for the D7 backport and mark this issue as fixed?
Comment #65
daffie commented@alexpott: Why do you want to have this issue closed and opening a new one for D7. It is must more easy just to set this one back to D7. They get all the info about the problem direct from this issue.
Comment #66
alexpott@daffie - this is the new policy. It exists for lots and lots of reasons - see https://www.drupal.org/core/backport-policy and #1145076: UNION queries don't support ORDER BY clauses
Comment #67
daffie commentedCreated #2772107: UNION queries don't support ORDER BY clauses for D7.
Comment #68
daffie commented@alexpott: Thank you for the explanation.
Comment #69
hass commentedWhen has this policy changed? In past we always moved cases to D7 after it was fixed in D8. This way we are loosing track of the issue that moved from D7 to D8 to get fixed there first.
Comment #70
Libero82 commentedTry it, work for me
https://www.drupal.org/node/2205391#comment-8522061
Comment #71
Libero82 commentedtry this for union in ORDER BY
$query = db_select('node', 'n')
->fields('n', array('nid', 'title'))
->condition('nid', 92);
$query2 = db_select('comment', 'c')
->fields('c', array('cid', 'subject'))
->condition('cid', 5);
$query2->orderBy('title', 'DESC'); // this
$query->union($query2);
Comment #72
daffie commentedThis will not work because the comment table does not have a column named "title".
Second the union operator return an unordered list. Whatever you put into an union operator you get an unordered list. You can however order the unordered list after the union operator. So moving
$query2->orderBy('title', 'DESC');to the bottom and changing it to $query instead of $query2 will work much better.