order by clause not working after shrinking database - sql-server-2008

Recently, I have shrink local database and size reduced from 6gb to 1 mb.
But after that some query doesn't work, those are already working in development and live server (in local, development and live sql version is same).
One of this query is
SELECT a.col1,
b.col2,
isnull(a.intPriority, 100) AS intPriority
FROM tab1 a
INNER JOIN tab2 b
ON a.id = b.id
UNION
SELECT a.col1,
b.col2,
isnull(a.intPriority, 100) AS intPriority
FROM tab1 a
INNER JOIN tab2 b
ON a.id = b.id
ORDER BY a.intPriority
This query giving me an error:
ORDER BY items must appear in the select list if the statement contains a UNION, INTERSECT or EXCEPT operator.
Above query runs well in dev and live server, why not on local??
I know, suppose I changed order by to intPriority than problem will solved but its not solution. I have to change in my entire website.

I think you just need:
ORDER BY intPriority
Also I don't think this has anything at all to do with shrinking your database, but perhaps you upgraded from SQL Server 2000 as well? If so you can "get by" in the meantime by rolling your compat level back to 2000. Just to demonstrate, on SQL Server 2008:
SELECT name = COALESCE(a.name, '') FROM sys.objects AS a
UNION ALL
SELECT name = COALESCE(a.name, '') FROM sys.objects AS a
ORDER BY a.name;
Fails with:
ORDER BY items must appear in the select list if the statement contains a UNION, INTERSECT or EXCEPT operator.
But works after setting:
ALTER DATABASE my_db SET COMPATIBILITY_LEVEL = 80;
So you can set the compat level for your database back to 2000, and your invalid code will work in the meantime, but you really should FIX it, because eventually 80 won't be a valid compatibility level (it is no longer valid in SQL Server 2012) and because someone else might upgrade the compatibility level on the servers where this is already working (since this is typically one of the recommended steps after upgrading a database).

Related

MySQL 5.7 vs. 8 difference in LEFT JOIN processing

We are checking if we can upgrade our project database from MySQL 5.7 to v.8. The system is 7 years old and has tons of code... Today we got a slightly strange bug which did not appear on 5.7 (I wonder why). The buggy request is the following:
SELECT TableA.Amount, SUM(TableB.Amount) AS Amount2
FROM
TableA LEFT JOIN TableB ON TableA.ReservID = TableB.ReservID
WHERE
TableB.InvoiceID IS NULL
AND TableB.InvoiceStatusID = 2
AND TableB.PersonID = 389
AND TableB.PersonTypeID = 1
AND TableA.ReservID = 4657;
There is one record in TableA and no records in TableB for the given conditions.
I know that WHERE conditions are applied after joining the tables. So it is not a suprise for me that the query return NULL, NULL on MySQL8. But our developer (who's still sure that this query is Ok) just showed me that it returns 67667.65, NULL on MySQL 5.7!
So I got 2 questions at ones. 1. Why it works on 5.7 when all data must be filtered out by the WHERE conditions on non-existent (all null in joint table) Table2 fields? 2. Is there a way to make MySQL8 work in the same 'tolerant' way as I am sure there are many such 'genius' queries all over our old code?
The problem in your query is not the (left) join. While it makes it less clear to the reader that your left join is treated as a join, having the comparisons in the where clause is completely valid sql. Every database will treat your left join correctly as a join, and I don't think that MySQL (5.7 or 8.0) would give you a different result if you replace left join with a join, as the internal representation would not change.
Your query has a problem with the aggregation. select colA, sum(colB) without using group by colA will leave the value of colA unclear, see MySQL Handling of GROUP BY:
SELECT name, MAX(age) FROM t;
Without GROUP BY, there is a single group and it is nondeterministic which name value to choose for the group.
MySQL is about the only database system that will even allow you to run this query, a very special behaviour that generates a lot of questions on stackoverflow. Most other databases will complain about that column listed in the select - exactly for the reason you face right now: they don't really know what to return.
So the value you get for tablea.amount is basically random. While it usually depends on how MySQL executes the query internally (so it could depend on some optimization setting), it looks unlikely that you can convince MySQL 8 to return the number value there - and especially to make sure it is consistent in all similar queries you may have.
And I want to emphasize: the value null in MySQL 8 is also not deterministic - it could be something different.
To make a proper query, use an aggregate function for tablea.amount too, and depending on your requirements, fix your left join, e.g.
SELECT MAX(TableA.Amount) AS Amount,
SUM(TableB.Amount) AS Amount2
FROM TableA LEFT JOIN TableB
ON TableA.ReservID = TableB.ReservID
AND TableB.InvoiceID IS NULL
AND TableB.InvoiceStatusID = 2
AND TableB.PersonID = 389
AND TableB.PersonTypeID = 1
WHERE TableA.ReservID = 4657
This should give you the behaviour from MySQL 5.7, e.g. <value for amount>, null. If you use join, you should get null, null. Both cases will be deterministic.
Although using just SELECT TableA.Amount, SUM(...) ... LEFT JOIN ... (with a proper left join) will return the amount instead of null for MySQL 8 too, it is still not valid sql! MySQL will only allow it because ReservID = 4657 limits it to a single row in TableA using the primary key. So if you have to check all queries anyway, fix it properly.
i dont know the reason, why its working on 5.7. but to get your expected result you can do:
SELECT
TableA.Amount,
SUM(TableB.Amount) AS Amount2
FROM TableA
LEFT JOIN TableB
ON TableA.ReservID = TableB.ReservID
AND TableB.InvoiceID IS NULL
AND TableB.InvoiceStatusID = 2
AND TableB.PersonID = 389
AND TableB.PersonTypeID = 1
WHERE TableA.ReservID = 4657;

MySQL query with GROUP BY behaving differently between MySQL versions?

I have two MySQL tables - equipment and calibration, where equipment represents an inventory of equipment and calibration holds records for each equipment calibration. One equipment will have multiple calibrations.
In MySQL 5.5 the following query was fully working to identify equipment where the most recent calibration has expired:
SELECT * FROM equipment AS e
LEFT JOIN (
SELECT calibration_id, equipment_id, calibration_company, certificate_no, date_certified, date_nextdue
FROM (
SELECT calibration_id, equipment_id, calibration_company, certificate_no, date_certified, date_nextdue
FROM calibration
WHERE deleted=0
ORDER BY date_certified DESC
) AS a GROUP BY a.equipment_id
) AS c ON c.equipment_id=e.equipment_id
WHERE e.deleted=0 AND c.date_nextdue <= CURRENT_DATE()
However in MySQL 5.7 the same SQL query works but returns rows including the oldest calibration not the most recent.
I've been experimenting with different joins but all need the GROUP BY facility and that seems to be where this all goes wrong.
While the above is a fictional example I have a lot of queries that are very similar in structure and behaving the same way. My question in two parts is:
Why is this behaving differently in MySQL 5.7, and
What changes do I need to make to the SQL to get it to function as desired in MySQL 5.7?
Thank you for your help.
Your original query has non-aggregated columns in the select clause that do not belong to the group by clause. While MySQL might allow that, which value will be picked is actually undefined, meaning that it is not guaranteed to be consistent over consecutive executions.
Preventing developers from falling into this trap is one of the reason why MySQL enables ONLY_FULL_GROUP_BY by default starting version 5.7 (since your query is still running, it means that this sql mode was explicitly disabled in the configuration of your new database server).
If I understood your query correctly, you can use a correlated subquery instead:
select e.*
from equipments e
where (
select max(c.date_certified)
from calibration c
where c.equipment_id = e.equipment_id and c.deleted = 0
) <= current_date

Knowage autogenerated query understanding

I'm using knowage software for data analysis, I'm facing performance issues, now I'm watching 'dataset audit' log to see what queries does the system perform. I found this one that, to me, is a nonsense:
SELECT COUNT(*)
FROM
(select TOP(100) PERCENT "ATC_1" AS "ATC_1"
from
(SELECT [ID_AFo]
,[ATC]
,[ATC_1]
,[ATC_3]
,[ATC_4]
,[ATC_5]
FROM [AFO]
) T order by "ATC_1" ASC
) u
inner T query is the dataset definition query I entered that basically is a select * from [AFO] on my table, outer wrap are made by knowage (I never wrote them)
doesn't a select count (*) from T have performed the same calculation but avoiding a cexpensive order by?
EDIT:
Backend (data source) is MSSQL, cache server is MYSQL so frequent queries are on mysql
This query is equivalent to:
SELECT COUNT(*)
FROM [AFO];
The only reason that I can think of for constructing such a query is if the "100" could be set to another value. I'm not sure if SQL Server's optimizer is good enough to eliminate the ORDER BY in the subquery.

Is there ANY_VALUE capability for mysql 5.6?

currently im working with mysql 5.7 in development, and 5.6 in production. Each time i run a query with a group by in development i get some error like "Error Code: 1055. Expression #1 of SELECT list is not in GROUP BY "
Here is the query.
SELECT c.id, c.name, i.*
FROM countries c, images i
WHERE i.country_id = c.id
GROUP BY c.id; Fixed for 5.7;
SELECT c.id, c.name,
ANY_VALUE(i.url) url,
ANY_VALUE(i.lat) lat,
ANY_VALUE(i.lng) lng
FROM countries c, images i
WHERE i.country_id = c.id
GROUP BY c.id;
For solving that I use the mysql function from 5.7 ANY_VALUE, but the main issue is that its not available in mysql 5.6
So if I fix the sql statement for development i will get an error in production.
Do you know any solution or polifill for the ANY_VALUE function in mysql 5.6?
You're misusing the notorious nonstandard MySQL extension to GROUP BY. Standard SQL will always reject your query, because you're mentioning columns that aren't aggregates and aren't mentioned in GROUP BY. In your dev system you're trying to work around that with ANY_VALUE().
In production, you can turn off the ONLY_FULL_GROUP_BY MySQL Mode. Try doing this:
SET #mode := ##SESSION.sql_mode;
SET SESSION sql_mode = '';
/* your query here */
SET SESSION sql_mode = #mode;
This will allow MySQL to accept your query.
But look, your query isn't really correct. When you can persuade it to run, it returns a randomly chosen row from the images table. That sort of indeterminacy often causes confusion for users and your tech support crew.
Why not make the query better, so it chooses a particular image. If your images table has an autoincrement id column you can do this to select the "first" image.
SELECT c.id, c.name, i.*
FROM countries c
LEFT JOIN (
SELECT MIN(id) id, country_id
FROM images
GROUP BY country_id
) first ON c.id = first.country_id
LEFT JOIN images i ON first.id = i.id
That will return one row per country with a predictable image shown.
Instead of ANY_VALUE, you could use the MIN or MAX aggregate functions.
Alternatively, you might consider not setting the ONLY_FULL_GROUP_BY SQL mode, which is set by default for MySql 5.7, and is responsible for the difference you experience with MySql 5.6. Then you can delay the update of your queries until you have migrated all your environments to MySql 5.7.
Which of the two is the better option, is debatable, but in the long term it will be better to adapt your queries so they adhere to the ONLY_FULL_GROUP_BY rule. Using MIN or MAX can certainly be of use in doing that.
For decades you could write queries that were not valid in standard SQL but perfectly valid mysql
In standard SQL, a query that includes a GROUP BY clause cannot refer
to nonaggregated columns in the select list that are not named in the
GROUP BY clause. For example, this query is illegal in standard SQL
because the nonaggregated name column in the select list does not
appear in the GROUP BY:
SELECT o.custid, c.name, MAX(o.payment) FROM orders AS o, customers
AS c WHERE o.custid = c.custid GROUP BY o.custid; For the query to
be legal, the name column must be omitted from the select list or
named in the GROUP BY clause.
MySQL extends the standard SQL use of GROUP BY so that the select list
can refer to nonaggregated columns not named in the GROUP BY clause.
This comes from the Mysql 5.6 manual's page on GROUP BY. If you look at the same page for 5.7.6 you see that things have changed. And changed dramatically!!
That page also gives you the solution. Disable ONLY_FULL_GROUP_BY That will make it possible for your old 5.6 query to work on 5.7.6 (remove ANY_VALUE from your query since it's not available in 5.7.6 but use the ONLY_FULL_GROUP_BY instead).

subselect sql query doesn't work on mysql 4

The following sql query works fine on my development server running mysql 5, but when I try it on my live server running mysql 4 it throws an error, can anyone help show me how to adapt my query to run on mysql 4?
select * FROM Properties WHERE propertyid IN (select id from todelete)
Subqueries are not supported in versions lower than Mysql 4.1.
http://dev.mysql.com/doc/refman/4.1/en/subqueries.html
SELECT * FROM Properties RIGHT JOIN todelete ON (Properties.propertyid = todelete.id);
To delete all rows from Properties which match this condition use this:
DELETE Properties FROM Properties INNER JOIN todelete ON (Properties.propertyid = todelete.id);
See T-SQL: Selecting rows to delete via joins